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(" while /sbin/ip rule del dev $INTERFACE; do :; done\n")
175 script.write(" /sbin/ip rule add dev $INTERFACE table $LINK\n")
176 script.write(" /sbin/ip route replace $IP table $LINK proto static"
179 script.write(" /sbin/ip route replace $IP proto static"
181 interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
182 interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
183 script.write(" if [ -d %s ]; then\n" % interface_v4_conf)
184 script.write(" echo 1 > %s/proxy_arp\n" % interface_v4_conf)
185 script.write(" echo 1 > %s/forwarding\n" % interface_v4_conf)
186 script.write(" fi\n")
187 script.write(" if [ -d %s ]; then\n" % interface_v6_conf)
188 script.write(" echo 1 > %s/proxy_ndp\n" % interface_v6_conf)
189 script.write(" echo 1 > %s/forwarding\n" % interface_v6_conf)
190 script.write(" fi\n")
191 script.write("fi\n\n")
192 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
193 # mounted noexec sometimes, so we'll have to find another place.
194 (tmpfd, tmpfile_name) = tempfile.mkstemp()
195 tmpfile = os.fdopen(tmpfd, 'w')
197 tmpfile.write(script.getvalue())
200 os.chmod(tmpfile_name, 0755)
203 def ListInstances(self):
204 """Get the list of running instances.
206 We can do this by listing our live instances directory and
207 checking whether the associated kvm process is still alive.
211 for name in os.listdir(self._PIDS_DIR):
212 filename = "%s/%s" % (self._PIDS_DIR, name)
213 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
217 def GetInstanceInfo(self, instance_name):
218 """Get instance properties.
220 @param instance_name: the instance name
222 @return: tuple (name, id, memory, vcpus, stat, times)
225 pidfile, pid, alive = self._InstancePidAlive(instance_name)
229 cmdline_file = "/proc/%s/cmdline" % pid
231 cmdline = utils.ReadFile(cmdline_file)
232 except EnvironmentError, err:
233 raise errors.HypervisorError("Failed to list instance %s: %s" %
234 (instance_name, err))
241 arg_list = cmdline.split('\x00')
243 arg = arg_list.pop(0)
245 memory = int(arg_list.pop(0))
247 vcpus = int(arg_list.pop(0))
249 return (instance_name, pid, memory, vcpus, stat, times)
251 def GetAllInstancesInfo(self):
252 """Get properties of all instances.
254 @return: list of tuples (name, id, memory, vcpus, stat, times)
258 for name in os.listdir(self._PIDS_DIR):
259 filename = "%s/%s" % (self._PIDS_DIR, name)
260 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
262 info = self.GetInstanceInfo(name)
263 except errors.HypervisorError, err:
270 def _GenerateKVMRuntime(self, instance, block_devices):
271 """Generate KVM information to start an instance.
274 pidfile, pid, alive = self._InstancePidAlive(instance.name)
275 kvm = constants.KVM_PATH
277 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
278 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
279 kvm_cmd.extend(['-pidfile', pidfile])
280 # used just by the vnc server, if enabled
281 kvm_cmd.extend(['-name', instance.name])
282 kvm_cmd.extend(['-daemonize'])
283 if not instance.hvparams[constants.HV_ACPI]:
284 kvm_cmd.extend(['-no-acpi'])
286 hvp = instance.hvparams
287 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
288 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
289 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
292 kvm_cmd.extend(['-boot', 'n'])
294 disk_type = hvp[constants.HV_DISK_TYPE]
295 if disk_type == constants.HT_DISK_PARAVIRTUAL:
296 if_val = ',if=virtio'
298 if_val = ',if=%s' % disk_type
299 for cfdev, dev_path in block_devices:
300 if cfdev.mode != constants.DISK_RDWR:
301 raise errors.HypervisorError("Instance has read-only disks which"
302 " are not supported by KVM")
303 # TODO: handle FD_LOOP and FD_BLKTAP (?)
305 kvm_cmd.extend(['-boot', 'c'])
306 boot_val = ',boot=on'
307 # We only boot from the first disk
312 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
313 kvm_cmd.extend(['-drive', drive_val])
315 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
317 options = ',format=raw,media=cdrom'
319 kvm_cmd.extend(['-boot', 'd'])
320 options = '%s,boot=on' % options
322 options = '%s,if=virtio' % options
323 drive_val = 'file=%s%s' % (iso_image, options)
324 kvm_cmd.extend(['-drive', drive_val])
326 kernel_path = hvp[constants.HV_KERNEL_PATH]
328 kvm_cmd.extend(['-kernel', kernel_path])
329 initrd_path = hvp[constants.HV_INITRD_PATH]
331 kvm_cmd.extend(['-initrd', initrd_path])
332 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
333 hvp[constants.HV_KERNEL_ARGS]]
334 if hvp[constants.HV_SERIAL_CONSOLE]:
335 root_append.append('console=ttyS0,38400')
336 kvm_cmd.extend(['-append', ' '.join(root_append)])
338 mouse_type = hvp[constants.HV_USB_MOUSE]
340 kvm_cmd.extend(['-usb'])
341 kvm_cmd.extend(['-usbdevice', mouse_type])
343 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
345 if utils.IsValidIP(vnc_bind_address):
346 if instance.network_port > constants.VNC_BASE_PORT:
347 display = instance.network_port - constants.VNC_BASE_PORT
348 if vnc_bind_address == '0.0.0.0':
349 vnc_arg = ':%d' % (display)
351 vnc_arg = '%s:%d' % (vnc_bind_address, display)
353 logging.error("Network port is not a valid VNC display (%d < %d)."
354 " Not starting VNC" %
355 (instance.network_port,
356 constants.VNC_BASE_PORT))
359 # Only allow tls and other option when not binding to a file, for now.
360 # kvm/qemu gets confused otherwise about the filename to use.
362 if hvp[constants.HV_VNC_TLS]:
363 vnc_append = '%s,tls' % vnc_append
364 if hvp[constants.HV_VNC_X509_VERIFY]:
365 vnc_append = '%s,x509verify=%s' % (vnc_append,
366 hvp[constants.HV_VNC_X509])
367 elif hvp[constants.HV_VNC_X509]:
368 vnc_append = '%s,x509=%s' % (vnc_append,
369 hvp[constants.HV_VNC_X509])
370 if hvp[constants.HV_VNC_PASSWORD_FILE]:
371 vnc_append = '%s,password' % vnc_append
373 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
376 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
378 kvm_cmd.extend(['-vnc', vnc_arg])
380 kvm_cmd.extend(['-nographic'])
382 monitor_dev = ("unix:%s,server,nowait" %
383 self._InstanceMonitor(instance.name))
384 kvm_cmd.extend(['-monitor', monitor_dev])
385 if hvp[constants.HV_SERIAL_CONSOLE]:
386 serial_dev = ('unix:%s,server,nowait' %
387 self._InstanceSerial(instance.name))
388 kvm_cmd.extend(['-serial', serial_dev])
390 kvm_cmd.extend(['-serial', 'none'])
392 # Save the current instance nics, but defer their expansion as parameters,
393 # as we'll need to generate executable temp files for them.
394 kvm_nics = instance.nics
397 return (kvm_cmd, kvm_nics, hvparams)
399 def _WriteKVMRuntime(self, instance_name, data):
400 """Write an instance's KVM runtime
404 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
406 except EnvironmentError, err:
407 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
409 def _ReadKVMRuntime(self, instance_name):
410 """Read an instance's KVM runtime
414 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
415 except EnvironmentError, err:
416 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
419 def _SaveKVMRuntime(self, instance, kvm_runtime):
420 """Save an instance's KVM runtime
423 kvm_cmd, kvm_nics, hvparams = kvm_runtime
424 serialized_nics = [nic.ToDict() for nic in kvm_nics]
425 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
426 self._WriteKVMRuntime(instance.name, serialized_form)
428 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
429 """Load an instance's KVM runtime
432 if not serialized_runtime:
433 serialized_runtime = self._ReadKVMRuntime(instance.name)
434 loaded_runtime = serializer.Load(serialized_runtime)
435 kvm_cmd, serialized_nics, hvparams = loaded_runtime
436 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
437 return (kvm_cmd, kvm_nics, hvparams)
439 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
440 """Execute a KVM cmd, after completing it with some last minute data
442 @type incoming: tuple of strings
443 @param incoming: (target_host_ip, port)
446 pidfile, pid, alive = self._InstancePidAlive(instance.name)
447 hvp = instance.hvparams
449 raise errors.HypervisorError("Failed to start instance %s: %s" %
450 (instance.name, "already running"))
454 kvm_cmd, kvm_nics, hvparams = kvm_runtime
457 kvm_cmd.extend(['-net', 'none'])
459 nic_type = hvparams[constants.HV_NIC_TYPE]
460 if nic_type == constants.HT_NIC_PARAVIRTUAL:
461 nic_model = "model=virtio"
463 nic_model = "model=%s" % nic_type
465 for nic_seq, nic in enumerate(kvm_nics):
466 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
467 script = self._WriteNetScript(instance, nic_seq, nic)
468 kvm_cmd.extend(['-net', nic_val])
469 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
470 temp_files.append(script)
473 target, port = incoming
474 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
476 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
480 vnc_pwd = utils.ReadFile(vnc_pwd_file)
481 except EnvironmentError, err:
482 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
483 % (vnc_pwd_file, err))
485 result = utils.RunCmd(kvm_cmd)
487 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
488 (instance.name, result.fail_reason,
491 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
492 raise errors.HypervisorError("Failed to start instance %s: %s" %
496 change_cmd = 'change vnc password %s' % vnc_pwd
497 self._CallMonitorCommand(instance.name, change_cmd)
499 for filename in temp_files:
500 utils.RemoveFile(filename)
502 def StartInstance(self, instance, block_devices):
503 """Start an instance.
506 pidfile, pid, alive = self._InstancePidAlive(instance.name)
508 raise errors.HypervisorError("Failed to start instance %s: %s" %
509 (instance.name, "already running"))
511 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
512 self._SaveKVMRuntime(instance, kvm_runtime)
513 self._ExecuteKVMRuntime(instance, kvm_runtime)
515 def _CallMonitorCommand(self, instance_name, command):
516 """Invoke a command on the instance monitor.
519 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
520 (utils.ShellQuote(command),
521 constants.SOCAT_PATH,
522 utils.ShellQuote(self._InstanceMonitor(instance_name))))
523 result = utils.RunCmd(socat)
525 msg = ("Failed to send command '%s' to instance %s."
526 " output: %s, error: %s, fail_reason: %s" %
527 (command, instance_name,
528 result.stdout, result.stderr, result.fail_reason))
529 raise errors.HypervisorError(msg)
533 def StopInstance(self, instance, force=False, retry=False):
537 pidfile, pid, alive = self._InstancePidAlive(instance.name)
538 if pid > 0 and alive:
539 if force or not instance.hvparams[constants.HV_ACPI]:
540 utils.KillProcess(pid)
542 self._CallMonitorCommand(instance.name, 'system_powerdown')
544 if not utils.IsProcessAlive(pid):
545 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
550 def RebootInstance(self, instance):
551 """Reboot an instance.
554 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
555 # socket the instance will stop, but now power up again. So we'll resort
556 # to shutdown and restart.
557 pidfile, pid, alive = self._InstancePidAlive(instance.name)
559 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
561 # StopInstance will delete the saved KVM runtime so:
562 # ...first load it...
563 kvm_runtime = self._LoadKVMRuntime(instance)
564 # ...now we can safely call StopInstance...
565 if not self.StopInstance(instance):
566 self.StopInstance(instance, force=True)
567 # ...and finally we can save it again, and execute it...
568 self._SaveKVMRuntime(instance, kvm_runtime)
569 self._ExecuteKVMRuntime(instance, kvm_runtime)
571 def MigrationInfo(self, instance):
572 """Get instance information to perform a migration.
574 @type instance: L{objects.Instance}
575 @param instance: instance to be migrated
577 @return: content of the KVM runtime file
580 return self._ReadKVMRuntime(instance.name)
582 def AcceptInstance(self, instance, info, target):
583 """Prepare to accept an instance.
585 @type instance: L{objects.Instance}
586 @param instance: instance to be accepted
588 @param info: content of the KVM runtime file on the source node
590 @param target: target host (usually ip), on this node
593 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
594 incoming_address = (target, constants.KVM_MIGRATION_PORT)
595 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
597 def FinalizeMigration(self, instance, info, success):
598 """Finalize an instance migration.
600 Stop the incoming mode KVM.
602 @type instance: L{objects.Instance}
603 @param instance: instance whose migration is being aborted
607 self._WriteKVMRuntime(instance.name, info)
609 self.StopInstance(instance, force=True)
611 def MigrateInstance(self, instance, target, live):
612 """Migrate an instance to a target node.
614 The migration will not be attempted if the instance is not
617 @type instance: L{objects.Instance}
618 @param instance: the instance to be migrated
620 @param target: ip address of the target node
622 @param live: perform a live migration
625 instance_name = instance.name
626 pidfile, pid, alive = self._InstancePidAlive(instance_name)
628 raise errors.HypervisorError("Instance not running, cannot migrate")
631 self._CallMonitorCommand(instance_name, 'stop')
633 migrate_command = ('migrate -d tcp:%s:%s' %
634 (target, constants.KVM_MIGRATION_PORT))
635 self._CallMonitorCommand(instance_name, migrate_command)
637 info_command = 'info migrate'
640 result = self._CallMonitorCommand(instance_name, info_command)
641 match = self._MIGRATION_STATUS_RE.search(result.stdout)
643 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
646 status = match.group(1)
647 if status == 'completed':
649 elif status == 'active':
651 elif status == 'failed' or status == 'cancelled':
653 self._CallMonitorCommand(instance_name, 'cont')
654 raise errors.HypervisorError("Migration %s at the kvm level" %
657 logging.info("KVM: unknown migration status '%s'" % status)
660 utils.KillProcess(pid)
661 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
663 def GetNodeInfo(self):
664 """Return information about the node.
666 This is just a wrapper over the base GetLinuxNodeInfo method.
668 @return: a dict with the following keys (values in MiB):
669 - memory_total: the total memory size on the node
670 - memory_free: the available memory on the node for instances
671 - memory_dom0: the memory used by the node itself, if available
674 return self.GetLinuxNodeInfo()
677 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
678 """Return a command for connecting to the console of an instance.
681 if hvparams[constants.HV_SERIAL_CONSOLE]:
682 # FIXME: The socat shell is not perfect. In particular the way we start
683 # it ctrl+c will close it, rather than being passed to the other end.
684 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
685 # will be no way of exiting socat (except killing it from another shell)
686 # and ctrl+c doesn't work anyway, printing ^C rather than being
687 # interpreted by kvm. For now we'll leave it this way, which at least
688 # allows a minimal interaction and changes on the machine.
689 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
690 (constants.SOCAT_PATH,
691 utils.ShellQuote(cls._InstanceSerial(instance.name))))
693 shell_command = "echo 'No serial shell for instance %s'" % instance.name
695 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
697 if instance.network_port > constants.VNC_BASE_PORT:
698 display = instance.network_port - constants.VNC_BASE_PORT
699 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
700 " (display: %d)'" % (vnc_bind_address,
701 instance.network_port,
703 shell_command = "%s; %s" % (vnc_command, shell_command)
708 """Verify the hypervisor.
710 Check that the binary exists.
713 if not os.path.exists(constants.KVM_PATH):
714 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
715 if not os.path.exists(constants.SOCAT_PATH):
716 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
720 def CheckParameterSyntax(cls, hvparams):
721 """Check the given parameters for validity.
724 @param hvparams: dictionary with parameter names/value
725 @raise errors.HypervisorError: when a parameter is not valid
728 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
730 kernel_path = hvparams[constants.HV_KERNEL_PATH]
732 if not hvparams[constants.HV_ROOT_PATH]:
733 raise errors.HypervisorError("Need a root partition for the instance,"
734 " if a kernel is defined")
736 if (hvparams[constants.HV_VNC_X509_VERIFY] and
737 not hvparams[constants.HV_VNC_X509]):
738 raise errors.HypervisorError("%s must be defined, if %s is" %
739 (constants.HV_VNC_X509,
740 constants.HV_VNC_X509_VERIFY))
742 boot_order = hvparams[constants.HV_BOOT_ORDER]
744 if (boot_order == constants.HT_BO_CDROM and
745 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
746 raise errors.HypervisorError("Cannot boot from cdrom without an"
748 if (boot_order == constants.HT_BO_NETWORK and
749 hvparams[constants.HV_NIC_TYPE] == constants.HT_NIC_PARAVIRTUAL):
750 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
751 " change the NIC type.")
754 def PowercycleNode(cls):
755 """KVM powercycle, just a wrapper over Linux powercycle.
758 cls.LinuxPowercycle()