Commit 2a6469d5 authored by Alexander Schreiber's avatar Alexander Schreiber
Browse files

Proof-of-Concept HVM support for Ganeti.

This patch implements a first proof-of-concept for HVM support in Ganeti.
Due to the nature of this patch, it is intended for test environments
only.

Reviewed-by: iustinp
parent 01121d61
......@@ -499,6 +499,12 @@ class LUInitCluster(LogicalUnit):
if config.ConfigWriter.IsCluster():
raise errors.OpPrereqError("Cluster is already initialised")
if self.op.hypervisor_type == constants.HT_XEN_HVM31:
if not os.path.exists(constants.VNC_PASSWORD_FILE):
raise errors.OpPrereqError("Please prepare the cluster VNC"
"password file %s" %
constants.VNC_PASSWORD_FILE)
self.hostname = hostname = utils.HostInfo()
if hostname.ip.startswith("127."):
......@@ -1470,6 +1476,11 @@ class LUAddNode(LogicalUnit):
primary_ip=primary_ip,
secondary_ip=secondary_ip)
if self.sstore.GetHypervisorType() == constants.HT_XEN_HVM31:
if not os.path.exists(constants.VNC_PASSWORD_FILE):
raise errors.OpPrereqError("Cluster VNC password file %s missing" %
constants.VNC_PASSWORD_FILE)
def Exec(self, feedback_fn):
"""Adds the new node to the cluster.
......@@ -1589,6 +1600,8 @@ class LUAddNode(LogicalUnit):
(fname, to_node))
to_copy = ss.GetFileList()
if self.sstore.GetHypervisorType() == constants.HT_XEN_HVM31:
to_copy.append(constants.VNC_PASSWORD_FILE)
for fname in to_copy:
if not ssh.CopyFileToNode(node, fname):
logger.Error("could not copy file %s to node %s" % (fname, node))
......@@ -3028,7 +3041,11 @@ class LUCreateInstance(LogicalUnit):
if self.inst_ip is not None:
nic.ip = self.inst_ip
network_port = None # placeholder assignment for later
ht_kind = self.sstore.GetHypervisorType()
if ht_kind in constants.HTS_REQ_PORT:
network_port = self.cfg.AllocatePort()
else:
network_port = None
disks = _GenerateDiskTemplate(self.cfg,
self.op.disk_template,
......
......@@ -151,5 +151,9 @@ INSTANCE_REBOOT_FULL = "full"
# Hypervisor constants
HT_XEN_PVM30 = "xen-3.0"
HT_FAKE = "fake"
HT_XEN_HVM31 = "xen-hvm-3.1"
HYPER_TYPES = frozenset([HT_XEN_PVM30, HT_FAKE, HT_XEN_HVM31])
HTS_REQ_PORT = frozenset([HT_XEN_HVM31])
HYPER_TYPES = frozenset([HT_XEN_PVM30, HT_FAKE])
HT_HVM_VNC_BASE_PORT = 5900
VNC_PASSWORD_FILE = _autoconf.SYSCONFDIR + "/ganeti/vnc-cluster-password"
......@@ -31,6 +31,7 @@ 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
......@@ -46,6 +47,8 @@ def GetHypervisor():
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()
......@@ -540,3 +543,102 @@ class FakeHypervisor(BaseHypervisor):
"""
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")
config.write("boot = 'dc'\n")
config.write("sdl = 0\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))
......@@ -257,8 +257,11 @@ commands = {
" addresses",
metavar="ADDRESS", default=None),
make_option("-t", "--hypervisor-type", dest="hypervisor_type",
help="Specify the hypervisor type (xen-3.0, fake)",
metavar="TYPE", choices=["xen-3.0", "fake"],
help="Specify the hypervisor type "
"(xen-3.0, fake, xen-hvm-3.1)",
metavar="TYPE", choices=["xen-3.0",
"fake",
"xen-hvm-3.1"],
default="xen-3.0",),
make_option("-m", "--mac-prefix", dest="mac_prefix",
help="Specify the mac prefix for the instance IP"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment