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: hv_base.OPT_FILE_CHECK,
53 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
54 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
55 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
56 constants.HV_ACPI: hv_base.NO_CHECK,
57 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
58 constants.HV_VNC_BIND_ADDRESS:
59 (False, lambda x: (utils.IsValidIP(x) or utils.IsNormAbsPath(x)),
60 "the VNC bind address must be either a valid IP address or an absolute"
61 " pathname", None, None),
62 constants.HV_VNC_TLS: hv_base.NO_CHECK,
63 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
64 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
65 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
66 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
67 constants.HV_BOOT_ORDER:
68 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
69 constants.HV_NIC_TYPE:
70 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
71 constants.HV_DISK_TYPE:
72 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
73 constants.HV_USB_MOUSE:
74 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
77 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
80 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
87 hv_base.BaseHypervisor.__init__(self)
88 # Let's make sure the directories we need exist, even if the RUN_DIR lives
89 # in a tmpfs filesystem or has been otherwise wiped out.
90 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
91 utils.EnsureDirs(dirs)
93 def _InstancePidAlive(self, instance_name):
94 """Returns the instance pid and pidfile
97 pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
98 pid = utils.ReadPidFile(pidfile)
99 alive = utils.IsProcessAlive(pid)
101 return (pidfile, pid, alive)
104 def _InstanceMonitor(cls, instance_name):
105 """Returns the instance monitor socket name
108 return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
111 def _InstanceSerial(cls, instance_name):
112 """Returns the instance serial socket name
115 return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
118 def _InstanceKVMRuntime(cls, instance_name):
119 """Returns the instance KVM runtime filename
122 return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
125 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
126 """Removes an instance's rutime sockets/files.
129 utils.RemoveFile(pidfile)
130 utils.RemoveFile(cls._InstanceMonitor(instance_name))
131 utils.RemoveFile(cls._InstanceSerial(instance_name))
132 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
134 def _WriteNetScript(self, instance, seq, nic):
135 """Write a script to connect a net interface to the proper bridge.
137 This can be used by any qemu-type hypervisor.
139 @param instance: instance we're acting on
140 @type instance: instance object
141 @param seq: nic sequence number
143 @param nic: nic we're acting on
144 @type nic: nic object
145 @return: netscript file name
150 script.write("#!/bin/sh\n")
151 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
152 script.write("export INSTANCE=%s\n" % instance.name)
153 script.write("export MAC=%s\n" % nic.mac)
155 script.write("export IP=%s\n" % nic.ip)
156 script.write("export MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
157 if nic.nicparams[constants.NIC_LINK]:
158 script.write("export LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
159 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
160 script.write("export BRIDGE=%s\n" % nic.nicparams[constants.NIC_LINK])
161 script.write("export INTERFACE=$1\n")
162 # TODO: make this configurable at ./configure time
163 script.write("if [ -x '%s' ]; then\n" % self._KVM_NETWORK_SCRIPT)
164 script.write(" # Execute the user-specific vif file\n")
165 script.write(" %s\n" % self._KVM_NETWORK_SCRIPT)
166 script.write("else\n")
167 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
168 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
169 script.write(" # Connect the interface to the bridge\n")
170 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
171 elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
172 script.write(" # Route traffic targeted at the IP to the interface\n")
173 if nic.nicparams[constants.NIC_LINK]:
174 script.write(" /sbin/ip route replace $IP/32 table $LINK"
177 script.write(" /sbin/ip route replace $IP/32 dev $INTERFACE\n")
178 interface_proxy_arp = "/proc/sys/net/ipv4/conf/$INTERFACE/proxy_arp"
179 interface_forwarding = "/proc/sys/net/ipv4/conf/$INTERFACE/forwarding"
180 script.write(" /bin/echo 1 > %s\n" % interface_proxy_arp)
181 script.write(" /bin/echo 1 > %s\n" % interface_forwarding)
182 script.write("fi\n\n")
183 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
184 # mounted noexec sometimes, so we'll have to find another place.
185 (tmpfd, tmpfile_name) = tempfile.mkstemp()
186 tmpfile = os.fdopen(tmpfd, 'w')
188 tmpfile.write(script.getvalue())
191 os.chmod(tmpfile_name, 0755)
194 def ListInstances(self):
195 """Get the list of running instances.
197 We can do this by listing our live instances directory and
198 checking whether the associated kvm process is still alive.
202 for name in os.listdir(self._PIDS_DIR):
203 filename = "%s/%s" % (self._PIDS_DIR, name)
204 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
208 def GetInstanceInfo(self, instance_name):
209 """Get instance properties.
211 @param instance_name: the instance name
213 @return: tuple (name, id, memory, vcpus, stat, times)
216 pidfile, pid, alive = self._InstancePidAlive(instance_name)
220 cmdline_file = "/proc/%s/cmdline" % pid
222 cmdline = utils.ReadFile(cmdline_file)
223 except EnvironmentError, err:
224 raise errors.HypervisorError("Failed to list instance %s: %s" %
225 (instance_name, err))
232 arg_list = cmdline.split('\x00')
234 arg = arg_list.pop(0)
236 memory = int(arg_list.pop(0))
238 vcpus = int(arg_list.pop(0))
240 return (instance_name, pid, memory, vcpus, stat, times)
242 def GetAllInstancesInfo(self):
243 """Get properties of all instances.
245 @return: list of tuples (name, id, memory, vcpus, stat, times)
249 for name in os.listdir(self._PIDS_DIR):
250 filename = "%s/%s" % (self._PIDS_DIR, name)
251 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
253 info = self.GetInstanceInfo(name)
254 except errors.HypervisorError, err:
261 def _GenerateKVMRuntime(self, instance, block_devices):
262 """Generate KVM information to start an instance.
265 pidfile, pid, alive = self._InstancePidAlive(instance.name)
266 kvm = constants.KVM_PATH
268 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
269 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
270 kvm_cmd.extend(['-pidfile', pidfile])
271 # used just by the vnc server, if enabled
272 kvm_cmd.extend(['-name', instance.name])
273 kvm_cmd.extend(['-daemonize'])
274 if not instance.hvparams[constants.HV_ACPI]:
275 kvm_cmd.extend(['-no-acpi'])
277 hvp = instance.hvparams
278 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
279 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
280 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
283 kvm_cmd.extend(['-boot', 'n'])
285 disk_type = hvp[constants.HV_DISK_TYPE]
286 if disk_type == constants.HT_DISK_PARAVIRTUAL:
287 if_val = ',if=virtio'
289 if_val = ',if=%s' % disk_type
290 for cfdev, dev_path in block_devices:
291 if cfdev.mode != constants.DISK_RDWR:
292 raise errors.HypervisorError("Instance has read-only disks which"
293 " are not supported by KVM")
294 # TODO: handle FD_LOOP and FD_BLKTAP (?)
296 kvm_cmd.extend(['-boot', 'c'])
297 boot_val = ',boot=on'
298 # We only boot from the first disk
303 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
304 kvm_cmd.extend(['-drive', drive_val])
306 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
308 options = ',format=raw,media=cdrom'
310 kvm_cmd.extend(['-boot', 'd'])
311 options = '%s,boot=on' % options
313 options = '%s,if=virtio' % options
314 drive_val = 'file=%s%s' % (iso_image, options)
315 kvm_cmd.extend(['-drive', drive_val])
317 kernel_path = hvp[constants.HV_KERNEL_PATH]
319 kvm_cmd.extend(['-kernel', kernel_path])
320 initrd_path = hvp[constants.HV_INITRD_PATH]
322 kvm_cmd.extend(['-initrd', initrd_path])
323 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
324 hvp[constants.HV_KERNEL_ARGS]]
325 if hvp[constants.HV_SERIAL_CONSOLE]:
326 root_append.append('console=ttyS0,38400')
327 kvm_cmd.extend(['-append', ' '.join(root_append)])
329 mouse_type = hvp[constants.HV_USB_MOUSE]
331 kvm_cmd.extend(['-usb'])
332 kvm_cmd.extend(['-usbdevice', mouse_type])
334 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
336 if utils.IsValidIP(vnc_bind_address):
337 if instance.network_port > constants.VNC_BASE_PORT:
338 display = instance.network_port - constants.VNC_BASE_PORT
339 if vnc_bind_address == '0.0.0.0':
340 vnc_arg = ':%d' % (display)
342 vnc_arg = '%s:%d' % (vnc_bind_address, display)
344 logging.error("Network port is not a valid VNC display (%d < %d)."
345 " Not starting VNC" %
346 (instance.network_port,
347 constants.VNC_BASE_PORT))
350 # Only allow tls and other option when not binding to a file, for now.
351 # kvm/qemu gets confused otherwise about the filename to use.
353 if hvp[constants.HV_VNC_TLS]:
354 vnc_append = '%s,tls' % vnc_append
355 if hvp[constants.HV_VNC_X509_VERIFY]:
356 vnc_append = '%s,x509verify=%s' % (vnc_append,
357 hvp[constants.HV_VNC_X509])
358 elif hvp[constants.HV_VNC_X509]:
359 vnc_append = '%s,x509=%s' % (vnc_append,
360 hvp[constants.HV_VNC_X509])
361 if hvp[constants.HV_VNC_PASSWORD_FILE]:
362 vnc_append = '%s,password' % vnc_append
364 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
367 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
369 kvm_cmd.extend(['-vnc', vnc_arg])
371 kvm_cmd.extend(['-nographic'])
373 monitor_dev = 'unix:%s,server,nowait' % \
374 self._InstanceMonitor(instance.name)
375 kvm_cmd.extend(['-monitor', monitor_dev])
376 if hvp[constants.HV_SERIAL_CONSOLE]:
377 serial_dev = ('unix:%s,server,nowait' %
378 self._InstanceSerial(instance.name))
379 kvm_cmd.extend(['-serial', serial_dev])
381 kvm_cmd.extend(['-serial', 'none'])
383 # Save the current instance nics, but defer their expansion as parameters,
384 # as we'll need to generate executable temp files for them.
385 kvm_nics = instance.nics
388 return (kvm_cmd, kvm_nics, hvparams)
390 def _WriteKVMRuntime(self, instance_name, data):
391 """Write an instance's KVM runtime
395 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
397 except EnvironmentError, err:
398 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
400 def _ReadKVMRuntime(self, instance_name):
401 """Read an instance's KVM runtime
405 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
406 except EnvironmentError, err:
407 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
410 def _SaveKVMRuntime(self, instance, kvm_runtime):
411 """Save an instance's KVM runtime
414 kvm_cmd, kvm_nics, hvparams = kvm_runtime
415 serialized_nics = [nic.ToDict() for nic in kvm_nics]
416 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
417 self._WriteKVMRuntime(instance.name, serialized_form)
419 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
420 """Load an instance's KVM runtime
423 if not serialized_runtime:
424 serialized_runtime = self._ReadKVMRuntime(instance.name)
425 loaded_runtime = serializer.Load(serialized_runtime)
426 kvm_cmd, serialized_nics, hvparams = loaded_runtime
427 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
428 return (kvm_cmd, kvm_nics, hvparams)
430 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
431 """Execute a KVM cmd, after completing it with some last minute data
433 @type incoming: tuple of strings
434 @param incoming: (target_host_ip, port)
437 pidfile, pid, alive = self._InstancePidAlive(instance.name)
438 hvp = instance.hvparams
440 raise errors.HypervisorError("Failed to start instance %s: %s" %
441 (instance.name, "already running"))
445 kvm_cmd, kvm_nics, hvparams = kvm_runtime
448 kvm_cmd.extend(['-net', 'none'])
450 nic_type = hvparams[constants.HV_NIC_TYPE]
451 if nic_type == constants.HT_NIC_PARAVIRTUAL:
452 nic_model = "model=virtio"
454 nic_model = "model=%s" % nic_type
456 for nic_seq, nic in enumerate(kvm_nics):
457 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
458 script = self._WriteNetScript(instance, nic_seq, nic)
459 kvm_cmd.extend(['-net', nic_val])
460 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
461 temp_files.append(script)
464 target, port = incoming
465 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
467 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
471 vnc_pwd = utils.ReadFile(vnc_pwd_file)
472 except EnvironmentError, err:
473 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
474 % (vnc_pwd_file, err))
476 result = utils.RunCmd(kvm_cmd)
478 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
479 (instance.name, result.fail_reason,
482 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
483 raise errors.HypervisorError("Failed to start instance %s: %s" %
487 change_cmd = 'change vnc password %s' % vnc_pwd
488 self._CallMonitorCommand(instance.name, change_cmd)
490 for filename in temp_files:
491 utils.RemoveFile(filename)
493 def StartInstance(self, instance, block_devices):
494 """Start an instance.
497 pidfile, pid, alive = self._InstancePidAlive(instance.name)
499 raise errors.HypervisorError("Failed to start instance %s: %s" %
500 (instance.name, "already running"))
502 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
503 self._SaveKVMRuntime(instance, kvm_runtime)
504 self._ExecuteKVMRuntime(instance, kvm_runtime)
506 def _CallMonitorCommand(self, instance_name, command):
507 """Invoke a command on the instance monitor.
510 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
511 (utils.ShellQuote(command),
512 constants.SOCAT_PATH,
513 utils.ShellQuote(self._InstanceMonitor(instance_name))))
514 result = utils.RunCmd(socat)
516 msg = ("Failed to send command '%s' to instance %s."
517 " output: %s, error: %s, fail_reason: %s" %
518 (command, instance_name,
519 result.stdout, result.stderr, result.fail_reason))
520 raise errors.HypervisorError(msg)
524 def StopInstance(self, instance, force=False, retry=False):
528 pidfile, pid, alive = self._InstancePidAlive(instance.name)
529 if pid > 0 and alive:
530 if force or not instance.hvparams[constants.HV_ACPI]:
531 utils.KillProcess(pid)
533 self._CallMonitorCommand(instance.name, 'system_powerdown')
535 if not utils.IsProcessAlive(pid):
536 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
541 def RebootInstance(self, instance):
542 """Reboot an instance.
545 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
546 # socket the instance will stop, but now power up again. So we'll resort
547 # to shutdown and restart.
548 pidfile, pid, alive = self._InstancePidAlive(instance.name)
550 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
552 # StopInstance will delete the saved KVM runtime so:
553 # ...first load it...
554 kvm_runtime = self._LoadKVMRuntime(instance)
555 # ...now we can safely call StopInstance...
556 if not self.StopInstance(instance):
557 self.StopInstance(instance, force=True)
558 # ...and finally we can save it again, and execute it...
559 self._SaveKVMRuntime(instance, kvm_runtime)
560 self._ExecuteKVMRuntime(instance, kvm_runtime)
562 def MigrationInfo(self, instance):
563 """Get instance information to perform a migration.
565 @type instance: L{objects.Instance}
566 @param instance: instance to be migrated
568 @return: content of the KVM runtime file
571 return self._ReadKVMRuntime(instance.name)
573 def AcceptInstance(self, instance, info, target):
574 """Prepare to accept an instance.
576 @type instance: L{objects.Instance}
577 @param instance: instance to be accepted
579 @param info: content of the KVM runtime file on the source node
581 @param target: target host (usually ip), on this node
584 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
585 incoming_address = (target, constants.KVM_MIGRATION_PORT)
586 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
588 def FinalizeMigration(self, instance, info, success):
589 """Finalize an instance migration.
591 Stop the incoming mode KVM.
593 @type instance: L{objects.Instance}
594 @param instance: instance whose migration is being aborted
598 self._WriteKVMRuntime(instance.name, info)
600 self.StopInstance(instance, force=True)
602 def MigrateInstance(self, instance_name, target, live):
603 """Migrate an instance to a target node.
605 The migration will not be attempted if the instance is not
608 @type instance_name: string
609 @param instance_name: name of the instance to be migrated
611 @param target: ip address of the target node
613 @param live: perform a live migration
616 pidfile, pid, alive = self._InstancePidAlive(instance_name)
618 raise errors.HypervisorError("Instance not running, cannot migrate")
621 self._CallMonitorCommand(instance_name, 'stop')
623 migrate_command = ('migrate -d tcp:%s:%s' %
624 (target, constants.KVM_MIGRATION_PORT))
625 self._CallMonitorCommand(instance_name, migrate_command)
627 info_command = 'info migrate'
630 result = self._CallMonitorCommand(instance_name, info_command)
631 match = self._MIGRATION_STATUS_RE.search(result.stdout)
633 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
636 status = match.group(1)
637 if status == 'completed':
639 elif status == 'active':
641 elif status == 'failed' or status == 'cancelled':
643 self._CallMonitorCommand(instance_name, 'cont')
644 raise errors.HypervisorError("Migration %s at the kvm level" %
647 logging.info("KVM: unknown migration status '%s'" % status)
650 utils.KillProcess(pid)
651 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
653 def GetNodeInfo(self):
654 """Return information about the node.
656 This is just a wrapper over the base GetLinuxNodeInfo method.
658 @return: a dict with the following keys (values in MiB):
659 - memory_total: the total memory size on the node
660 - memory_free: the available memory on the node for instances
661 - memory_dom0: the memory used by the node itself, if available
664 return self.GetLinuxNodeInfo()
667 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
668 """Return a command for connecting to the console of an instance.
671 if hvparams[constants.HV_SERIAL_CONSOLE]:
672 # FIXME: The socat shell is not perfect. In particular the way we start
673 # it ctrl+c will close it, rather than being passed to the other end.
674 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
675 # will be no way of exiting socat (except killing it from another shell)
676 # and ctrl+c doesn't work anyway, printing ^C rather than being
677 # interpreted by kvm. For now we'll leave it this way, which at least
678 # allows a minimal interaction and changes on the machine.
679 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
680 (constants.SOCAT_PATH,
681 utils.ShellQuote(cls._InstanceSerial(instance.name))))
683 shell_command = "echo 'No serial shell for instance %s'" % instance.name
685 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
687 if instance.network_port > constants.VNC_BASE_PORT:
688 display = instance.network_port - constants.VNC_BASE_PORT
689 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
690 " (display: %d)'" % (vnc_bind_address,
691 instance.network_port,
693 shell_command = "%s; %s" % (vnc_command, shell_command)
698 """Verify the hypervisor.
700 Check that the binary exists.
703 if not os.path.exists(constants.KVM_PATH):
704 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
705 if not os.path.exists(constants.SOCAT_PATH):
706 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
710 def CheckParameterSyntax(cls, hvparams):
711 """Check the given parameters for validity.
714 @param hvparams: dictionary with parameter names/value
715 @raise errors.HypervisorError: when a parameter is not valid
718 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
720 kernel_path = hvparams[constants.HV_KERNEL_PATH]
722 if not hvparams[constants.HV_ROOT_PATH]:
723 raise errors.HypervisorError("Need a root partition for the instance,"
724 " if a kernel is defined")
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 boot_order = hvparams[constants.HV_BOOT_ORDER]
734 if (boot_order == constants.HT_BO_CDROM and
735 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
736 raise errors.HypervisorError("Cannot boot from cdrom without an"
738 if (boot_order == constants.HT_BO_NETWORK and
739 hvparams[constants.HV_NIC_TYPE] == constants.HT_NIC_PARAVIRTUAL):
740 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
741 " change the NIC type.")
744 def PowercycleNode(cls):
745 """KVM powercycle, just a wrapper over Linux powercycle.
748 cls.LinuxPowercycle()