from ganeti import logger
from ganeti import ssconf
from ganeti import constants
+from ganeti import errors
from ganeti.errors import HypervisorError
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)
return cls()
@staticmethod
def _WriteConfigFile(instance, block_devices, extra_args):
- """A Xen instance config file.
+ """Write the Xen config file for the instance.
"""
raise NotImplementedError
raise HypervisorError("xm list failed, retries exceeded (%s): %s" %
(result.fail_reason, result.stderr))
- # skip over the heading and the domain 0 line (optional)
- if include_node:
- to_skip = 1
- else:
- to_skip = 2
- lines = result.stdout.splitlines()[to_skip:]
+ # skip over the heading
+ lines = result.stdout.splitlines()[1:]
result = []
for line in lines:
# The format of lines is:
except ValueError, err:
raise HypervisorError("Can't parse output of xm list,"
" line: %s, error: %s" % (line, err))
- result.append(data)
+
+ # skip the Domain-0 (optional)
+ if include_node or data[0] != 'Domain-0':
+ result.append(data)
+
return result
def ListInstances(self):
if not utils.CheckDaemonAlive('/var/run/xend.pid', 'xend'):
return "xend daemon is not running"
+ @staticmethod
+ def _GetConfigFileDiskData(disk_template, block_devices):
+ """Get disk directive for xen config file.
+
+ This method builds the xen config disk directive according to the
+ given disk_template and block_devices.
+
+ Args:
+ disk_template: String containing instance disk template
+ block_devices: List[tuple1,tuple2,...]
+ tuple: (cfdev, rldev)
+ cfdev: dict containing ganeti config disk part
+ rldev: ganeti.bdev.BlockDev object
+
+ Returns:
+ String containing disk directive for xen instance config file
+
+ """
+ FILE_DRIVER_MAP = {
+ constants.FD_LOOP: "file",
+ constants.FD_BLKTAP: "tap:aio",
+ }
+ disk_data = []
+ for cfdev, rldev in block_devices:
+ if cfdev.dev_type == constants.LD_FILE:
+ line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
+ rldev.dev_path, cfdev.iv_name)
+ else:
+ line = "'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
+ disk_data.append(line)
+
+ return disk_data
+
class XenPvmHypervisor(XenHypervisor):
"""Xen PVM hypervisor interface"""
- @staticmethod
- def _WriteConfigFile(instance, block_devices, extra_args):
- """Create a Xen instance config file.
+ @classmethod
+ def _WriteConfigFile(cls, 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")
- config.write("kernel = '%s'\n" % constants.XEN_KERNEL)
- if os.path.exists(constants.XEN_INITRD):
- config.write("ramdisk = '%s'\n" % constants.XEN_INITRD)
+
+ # 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.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("disk = [%s]\n" % ",".join(
+ cls._GetConfigFileDiskData(instance.disk_template,
+ block_devices)))
config.write("root = '/dev/sda ro'\n")
config.write("on_poweroff = 'destroy'\n")
config.write("on_reboot = 'restart'\n")
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()
+ 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
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)
"""
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"""
+
+ @classmethod
+ def _WriteConfigFile(cls, 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))
+ iso = "'file:/srv/ganeti/iso/hvm-install.iso,hdc:cdrom,r'"
+ config.write("disk = [%s, %s]\n" % (",".join(
+ cls._GetConfigFileDiskData(instance.disk_template,
+ block_devices)), 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))