-#!/usr/bin/python
+#
#
# Copyright (C) 2006, 2007 Google Inc.
from ganeti import utils
from ganeti import logger
from ganeti import ssconf
+from ganeti import constants
+from ganeti import errors
from ganeti.errors import HypervisorError
-_HT_XEN30 = "xen-3.0"
-_HT_FAKE = "fake"
-
-VALID_HTYPES = (_HT_XEN30, _HT_FAKE)
def GetHypervisor():
"""Return a Hypervisor instance.
"""
ht_kind = ssconf.SimpleStore().GetHypervisorType()
- if ht_kind == _HT_XEN30:
- cls = XenHypervisor
- elif ht_kind == _HT_FAKE:
+ if ht_kind == constants.HT_XEN_PVM30:
+ cls = XenPvmHypervisor
+ elif ht_kind == constants.HT_FAKE:
cls = FakeHypervisor
+ elif ht_kind == constants.HT_XEN_HVM31:
+ cls = XenHvmHypervisor
else:
- raise HypervisorError, "Unknown hypervisor type '%s'" % ht_kind
+ raise HypervisorError("Unknown hypervisor type '%s'" % ht_kind)
return cls()
"""Stop an instance."""
raise NotImplementedError
+ def RebootInstance(self, instance):
+ """Reboot an instance."""
+ raise NotImplementedError
+
def ListInstances(self):
"""Get the list of running instances."""
raise NotImplementedError
raise NotImplementedError
@staticmethod
- def GetShellCommandForConsole(instance_name):
+ def GetShellCommandForConsole(instance):
"""Return a command for connecting to the console of an instance.
"""
class XenHypervisor(BaseHypervisor):
- """Xen hypervisor interface"""
+ """Xen generic hypervisor interface
+
+ This is the Xen base class used for both Xen PVM and HVM. It contains
+ all the functionality that is identical for both.
+
+ """
@staticmethod
def _WriteConfigFile(instance, block_devices, extra_args):
- """Create a Xen 3.0 config file.
+ """Write the Xen config file for the instance.
"""
-
- config = StringIO()
- config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
- config.write("kernel = '/boot/vmlinuz-2.6-xenU'\n")
- config.write("memory = %d\n" % instance.memory)
- config.write("vcpus = %d\n" % instance.vcpus)
- config.write("name = '%s'\n" % instance.name)
-
- vif_data = []
- for nic in instance.nics:
- nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
- ip = getattr(nic, "ip", None)
- if ip is not None:
- nic_str += ", ip=%s" % ip
- vif_data.append("'%s'" % nic_str)
-
- config.write("vif = [%s]\n" % ",".join(vif_data))
-
- disk_data = ["'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
- for cfdev, rldev in block_devices]
- config.write("disk = [%s]\n" % ",".join(disk_data))
-
- config.write("root = '/dev/sda ro'\n")
- config.write("on_poweroff = 'destroy'\n")
- config.write("on_reboot = 'restart'\n")
- config.write("on_crash = 'restart'\n")
- if extra_args:
- config.write("extra = '%s'\n" % extra_args)
- # just in case it exists
- utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
- f = open("/etc/xen/%s" % instance.name, "w")
- f.write(config.getvalue())
- f.close()
- return True
+ raise NotImplementedError
@staticmethod
def _RemoveConfigFile(instance):
result = utils.RunCmd(["xm", "create", instance.name])
if result.failed:
- raise HypervisorError("Failed to start instance %s: %s" %
- (instance.name, result.fail_reason))
+ raise HypervisorError("Failed to start instance %s: %s (%s)" %
+ (instance.name, result.fail_reason, result.output))
def StopInstance(self, instance, force=False):
"""Stop an instance."""
raise HypervisorError("Failed to stop instance %s: %s" %
(instance.name, result.fail_reason))
+ def RebootInstance(self, instance):
+ """Reboot an instance."""
+ result = utils.RunCmd(["xm", "reboot", instance.name])
+
+ if result.failed:
+ raise HypervisorError("Failed to reboot instance %s: %s" %
+ (instance.name, result.fail_reason))
+
def GetNodeInfo(self):
"""Return information about the node.
return result
@staticmethod
- def GetShellCommandForConsole(instance_name):
+ def GetShellCommandForConsole(instance):
"""Return a command for connecting to the console of an instance.
"""
- return "xm console %s" % instance_name
+ raise NotImplementedError
def Verify(self):
return "xend daemon is not running"
+class XenPvmHypervisor(XenHypervisor):
+ """Xen PVM hypervisor interface"""
+
+ @staticmethod
+ def _WriteConfigFile(instance, block_devices, extra_args):
+ """Write the Xen config file for the instance.
+
+ """
+ config = StringIO()
+ config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
+
+ # kernel handling
+ if instance.kernel_path in (None, constants.VALUE_DEFAULT):
+ kpath = constants.XEN_KERNEL
+ else:
+ if not os.path.exists(instance.kernel_path):
+ raise errors.HypervisorError("The kernel %s for instance %s is"
+ " missing" % (instance.kernel_path,
+ instance.name))
+ kpath = instance.kernel_path
+ config.write("kernel = '%s'\n" % kpath)
+
+ # initrd handling
+ if instance.initrd_path in (None, constants.VALUE_DEFAULT):
+ if os.path.exists(constants.XEN_INITRD):
+ initrd_path = constants.XEN_INITRD
+ else:
+ initrd_path = None
+ elif instance.initrd_path == constants.VALUE_NONE:
+ initrd_path = None
+ else:
+ if not os.path.exists(instance.initrd_path):
+ raise errors.HypervisorError("The initrd %s for instance %s is"
+ " missing" % (instance.initrd_path,
+ instance.name))
+ initrd_path = instance.initrd_path
+
+ if initrd_path:
+ config.write("ramdisk = '%s'\n" % initrd_path)
+
+ # rest of the settings
+ config.write("memory = %d\n" % instance.memory)
+ config.write("vcpus = %d\n" % instance.vcpus)
+ config.write("name = '%s'\n" % instance.name)
+
+ vif_data = []
+ for nic in instance.nics:
+ nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
+ ip = getattr(nic, "ip", None)
+ if ip is not None:
+ nic_str += ", ip=%s" % ip
+ vif_data.append("'%s'" % nic_str)
+
+ config.write("vif = [%s]\n" % ",".join(vif_data))
+
+ disk_data = ["'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
+ for cfdev, rldev in block_devices]
+ config.write("disk = [%s]\n" % ",".join(disk_data))
+
+ config.write("root = '/dev/sda ro'\n")
+ config.write("on_poweroff = 'destroy'\n")
+ config.write("on_reboot = 'restart'\n")
+ config.write("on_crash = 'restart'\n")
+ if extra_args:
+ config.write("extra = '%s'\n" % extra_args)
+ # just in case it exists
+ utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
+ try:
+ f = open("/etc/xen/%s" % instance.name, "w")
+ try:
+ f.write(config.getvalue())
+ finally:
+ f.close()
+ except IOError, err:
+ raise errors.OpExecError("Cannot write Xen instance confile"
+ " file /etc/xen/%s: %s" % (instance.name, err))
+ return True
+
+ @staticmethod
+ def GetShellCommandForConsole(instance):
+ """Return a command for connecting to the console of an instance.
+
+ """
+ return "xm console %s" % instance.name
+
+
class FakeHypervisor(BaseHypervisor):
"""Fake hypervisor interface.
a real virtualisation software installed.
"""
-
- _ROOT_DIR = "/var/run/ganeti-fake-hypervisor"
+ _ROOT_DIR = constants.RUN_DIR + "/ganeti-fake-hypervisor"
def __init__(self):
BaseHypervisor.__init__(self)
(instance.name, "not running"))
utils.RemoveFile(file_name)
+ def RebootInstance(self, instance):
+ """Reboot an instance.
+
+ For the fake hypervisor, this does nothing.
+
+ """
+ return
+
def GetNodeInfo(self):
"""Return information about the node.
return result
@staticmethod
- def GetShellCommandForConsole(instance_name):
+ def GetShellCommandForConsole(instance):
"""Return a command for connecting to the console of an instance.
"""
"""
if not os.path.exists(self._ROOT_DIR):
return "The required directory '%s' does not exist." % self._ROOT_DIR
+
+
+class XenHvmHypervisor(XenHypervisor):
+ """Xen HVM hypervisor interface"""
+
+ @staticmethod
+ def _WriteConfigFile(instance, block_devices, extra_args):
+ """Create a Xen 3.1 HVM config file.
+
+ """
+ config = StringIO()
+ config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
+ config.write("kernel = '/usr/lib/xen/boot/hvmloader'\n")
+ config.write("builder = 'hvm'\n")
+ config.write("memory = %d\n" % instance.memory)
+ config.write("vcpus = %d\n" % instance.vcpus)
+ config.write("name = '%s'\n" % instance.name)
+ config.write("pae = 1\n")
+ config.write("acpi = 1\n")
+ config.write("apic = 1\n")
+ arch = os.uname()[4]
+ if '64' in arch:
+ config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
+ else:
+ config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
+ if instance.hvm_boot_order is None:
+ config.write("boot = '%s'\n" % constants.HT_HVM_DEFAULT_BOOT_ORDER)
+ else:
+ config.write("boot = '%s'\n" % instance.hvm_boot_order)
+ config.write("sdl = 0\n")
+ config.write("usb = 1\n");
+ config.write("usbdevice = 'tablet'\n");
+ config.write("vnc = 1\n")
+ config.write("vnclisten = '0.0.0.0'\n")
+
+ if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
+ display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
+ config.write("vncdisplay = %s\n" % display)
+ config.write("vncunused = 0\n")
+ else:
+ config.write("# vncdisplay = 1\n")
+ config.write("vncunused = 1\n")
+
+ try:
+ password_file = open(constants.VNC_PASSWORD_FILE, "r")
+ try:
+ password = password_file.readline()
+ finally:
+ password_file.close()
+ except IOError:
+ raise errors.OpExecError("failed to open VNC password file %s " %
+ constants.VNC_PASSWORD_FILE)
+
+ config.write("vncpasswd = '%s'\n" % password.rstrip())
+
+ config.write("serial = 'pty'\n")
+ config.write("localtime = 1\n")
+
+ vif_data = []
+ for nic in instance.nics:
+ nic_str = "mac=%s, bridge=%s, type=ioemu" % (nic.mac, nic.bridge)
+ ip = getattr(nic, "ip", None)
+ if ip is not None:
+ nic_str += ", ip=%s" % ip
+ vif_data.append("'%s'" % nic_str)
+
+ config.write("vif = [%s]\n" % ",".join(vif_data))
+
+ disk_data = ["'phy:%s,%s,w'" %
+ (rldev.dev_path, cfdev.iv_name.replace("sd", "ioemu:hd"))
+ for cfdev, rldev in block_devices]
+ iso = "'file:/srv/ganeti/iso/hvm-install.iso,hdc:cdrom,r'"
+ config.write("disk = [%s, %s]\n" % (",".join(disk_data), iso) )
+
+ config.write("on_poweroff = 'destroy'\n")
+ config.write("on_reboot = 'restart'\n")
+ config.write("on_crash = 'restart'\n")
+ if extra_args:
+ config.write("extra = '%s'\n" % extra_args)
+ # just in case it exists
+ utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
+ try:
+ f = open("/etc/xen/%s" % instance.name, "w")
+ try:
+ f.write(config.getvalue())
+ finally:
+ f.close()
+ except IOError, err:
+ raise errors.OpExecError("Cannot write Xen instance confile"
+ " file /etc/xen/%s: %s" % (instance.name, err))
+ return True
+
+ @staticmethod
+ def GetShellCommandForConsole(instance):
+ """Return a command for connecting to the console of an instance.
+
+ """
+ if instance.network_port is None:
+ raise errors.OpExecError("no console port defined for %s"
+ % instance.name)
+ else:
+ raise errors.OpExecError("no PTY console, connect to %s:%s via VNC"
+ % (instance.primary_node,
+ instance.network_port))