Implement the new hypervisor API in base/xen
authorIustin Pop <iustin@google.com>
Tue, 14 Oct 2008 10:19:40 +0000 (10:19 +0000)
committerIustin Pop <iustin@google.com>
Tue, 14 Oct 2008 10:19:40 +0000 (10:19 +0000)
This patch adds the new methods CheckParameterSyntax and the
ValidateParameters in the base and xen hypervisors. It also changes the
xen hypervisor to use the new hvparams field on instance.

Reviewed-by: imsnah

lib/hypervisor/hv_base.py
lib/hypervisor/hv_xen.py

index 6980767..ad760f6 100644 (file)
 
 """
 
+from ganeti import errors
+
+
 class BaseHypervisor(object):
   """Abstract virtualisation technology interface
 
-  The goal is that all aspects of the virtualisation technology must
-  be abstracted away from the rest of code.
+  The goal is that all aspects of the virtualisation technology are
+  abstracted away from the rest of code.
 
   """
+  PARAMETERS = []
+
   def __init__(self):
     pass
 
@@ -106,3 +111,38 @@ class BaseHypervisor(object):
 
     """
     raise NotImplementedError
+
+
+  @classmethod
+  def CheckParameterSyntax(cls, hvparams):
+    """Check the given parameters for validity.
+
+    This should check the passed set of parameters for
+    validity. Classes should extend, not replace, this function.
+
+    @type hvparams:  dict
+    @param hvparams: dictionary with parameter names/value
+    @raise errors.HypervisorError: when a parameter is not valid
+
+    """
+    for key in hvparams:
+      if key not in cls.PARAMETERS:
+        raise errors.HypervisorError("Hypervisor parameter '%s'"
+                                     " not supported" % key)
+    for key in cls.PARAMETERS:
+      if key not in hvparams:
+        raise errors.HypervisorError("Hypervisor parameter '%s'"
+                                     " missing" % key)
+
+  def ValidateParameters(self, hvparams):
+    """Check the given parameters for validity.
+
+    This should check the passed set of parameters for
+    validity. Classes should extend, not replace, this function.
+
+    @type hvparams:  dict
+    @param hvparams: dictionary with parameter names/value
+    @raise errors.HypervisorError: when a parameter is not valid
+
+    """
+    pass
index 9ff8e20..cea3fa8 100644 (file)
@@ -287,6 +287,54 @@ class XenHypervisor(hv_base.BaseHypervisor):
 class XenPvmHypervisor(XenHypervisor):
   """Xen PVM hypervisor interface"""
 
+  PARAMETERS = [
+    constants.HV_KERNEL_PATH,
+    constants.HV_INITRD_PATH,
+    ]
+
+  @classmethod
+  def CheckParameterSyntax(cls, hvparams):
+    """Check the given parameters for validity.
+
+    For the PVM hypervisor, this only check the existence of the
+    kernel.
+
+    @type hvparams:  dict
+    @param hvparams: dictionary with parameter names/value
+    @raise errors.HypervisorError: when a parameter is not valid
+
+    """
+    super(XenPvmHypervisor, cls).CheckParameterSyntax(hvparams)
+
+    if not hvparams[constants.HV_KERNEL_PATH]:
+      raise errors.HypervisorError("Need a kernel for the instance")
+
+    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
+      raise errors.HypervisorError("The kernel path must an absolute path")
+
+    if hvparams[constants.HV_INITRD_PATH]:
+      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
+        raise errors.HypervisorError("The initrd path must an absolute path"
+                                     ", if defined")
+
+  def ValidateParameters(self, hvparams):
+    """Check the given parameters for validity.
+
+    For the PVM hypervisor, this only check the existence of the
+    kernel.
+
+    """
+    super(XenPvmHypervisor, self).ValidateParameters(hvparams)
+
+    kernel_path = hvparams[constants.HV_KERNEL_PATH]
+    if not os.path.isfile(kernel_path):
+      raise errors.HypervisorError("Instance kernel '%s' not found or"
+                                   " not a file" % kernel_path)
+    initrd_path = hvparams[constants.HV_INITRD_PATH]
+    if initrd_path and not os.path.isfile(initrd_path):
+      raise errors.HypervisorError("Instance initrd '%s' not found or"
+                                   " not a file" % initrd_path)
+
   @classmethod
   def _WriteConfigFile(cls, instance, block_devices, extra_args):
     """Write the Xen config file for the instance.
@@ -296,31 +344,11 @@ class XenPvmHypervisor(XenHypervisor):
     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
+    kpath = instance.hvparams[constants.HV_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
-
+    initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
     if initrd_path:
       config.write("ramdisk = '%s'\n" % initrd_path)
 
@@ -364,6 +392,72 @@ class XenPvmHypervisor(XenHypervisor):
 class XenHvmHypervisor(XenHypervisor):
   """Xen HVM hypervisor interface"""
 
+  PARAMETERS = [
+    constants.HV_ACPI,
+    constants.HV_BOOT_ORDER,
+    constants.HV_CDROM_IMAGE_PATH,
+    constants.HV_DISK_TYPE,
+    constants.HV_NIC_TYPE,
+    constants.HV_PAE,
+    constants.HV_VNC_BIND_ADDRESS,
+    ]
+
+  @classmethod
+  def CheckParameterSyntax(cls, hvparams):
+    """Check the given parameter syntax.
+
+    """
+    super(XenHvmHypervisor, cls).CheckParameterSyntax(hvparams)
+    # boot order verification
+    boot_order = hvparams[constants.HV_BOOT_ORDER]
+    if len(boot_order.strip("acdn")) != 0:
+      raise errors.HypervisorError("Invalid boot order '%s' specified,"
+                                   " must be one or more of [acdn]" %
+                                   boot_order)
+    # device type checks
+    nic_type = hvparams[constants.HV_NIC_TYPE]
+    if nic_type not in constants.HT_HVM_VALID_NIC_TYPES:
+      raise errors.HypervisorError("Invalid NIC type %s specified for Xen HVM"
+                                   " hypervisor" % nic_type)
+    disk_type = hvparams[constants.HV_DISK_TYPE]
+    if disk_type not in constants.HT_HVM_VALID_DISK_TYPES:
+      raise errors.HypervisorError("Invalid disk type %s specified for Xen HVM"
+                                   " hypervisor" % disk_type)
+    # vnc_bind_address verification
+    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
+    if vnc_bind_address is not None:
+      if not utils.IsValidIP(vnc_bind_address):
+        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
+                                   " like a valid IP address" %
+                                   vnc_bind_address)
+
+    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
+    if iso_path and not os.path.isabs(iso_path):
+        raise errors.HypervisorError("The path to the HVM CDROM image must"
+                                     " be an absolute path or None, not %s" %
+                                     iso_path)
+
+  def ValidateParameters(self, hvparams):
+    """Check the given parameters for validity.
+
+    For the PVM hypervisor, this only check the existence of the
+    kernel.
+
+    @type hvparams:  dict
+    @param hvparams: dictionary with parameter names/value
+    @raise errors.HypervisorError: when a parameter is not valid
+
+    """
+    super(XenHvmHypervisor, self).ValidateParameters(hvparams)
+
+    # hvm_cdrom_image_path verification
+    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
+    if iso_path and not os.path.isfile(iso_path):
+        raise errors.HypervisorError("The HVM CDROM image must either be a"
+                                     " regular file or a symlink pointing to"
+                                     " an existing regular file, not %s" %
+                                     iso_path)
+
   @classmethod
   def _WriteConfigFile(cls, instance, block_devices, extra_args):
     """Create a Xen 3.1 HVM config file.
@@ -376,11 +470,11 @@ class XenHvmHypervisor(XenHypervisor):
     config.write("memory = %d\n" % instance.memory)
     config.write("vcpus = %d\n" % instance.vcpus)
     config.write("name = '%s'\n" % instance.name)
-    if instance.hvm_pae:
+    if instance.hvparams[constants.HV_PAE]:
       config.write("pae = 1\n")
     else:
       config.write("pae = 0\n")
-    if instance.hvm_acpi:
+    if instance.hvparams[constants.HV_ACPI]:
       config.write("acpi = 1\n")
     else:
       config.write("acpi = 0\n")
@@ -390,18 +484,19 @@ class XenHvmHypervisor(XenHypervisor):
       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:
+    if instance.hvparams[constants.HV_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("boot = '%s'\n" % instance.hvparams["boot_order"])
     config.write("sdl = 0\n")
     config.write("usb = 1\n")
     config.write("usbdevice = 'tablet'\n")
     config.write("vnc = 1\n")
-    if instance.vnc_bind_address is None:
+    if instance.hvparams[constants.HV_VNC_BIND_ADDRESS] is None:
       config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
     else:
-      config.write("vnclisten = '%s'\n" % instance.vnc_bind_address)
+      config.write("vnclisten = '%s'\n" %
+                   instance.hvparams["vnc_bind_address"])
 
     if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
       display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
@@ -427,15 +522,16 @@ class XenHvmHypervisor(XenHypervisor):
     config.write("localtime = 1\n")
 
     vif_data = []
+    nic_type = instance.hvparams[constants.HV_NIC_TYPE]
+    if nic_type is None:
+      # ensure old instances don't change
+      nic_type_str = ", type=ioemu"
+    elif nic_type == constants.HT_HVM_DEV_PARAVIRTUAL:
+      nic_type_str = ", type=paravirtualized"
+    else:
+      nic_type_str = ", model=%s, type=ioemu" % nic_type
     for nic in instance.nics:
-      if instance.hvm_nic_type is None: # ensure old instances don't change
-        nic_type = ", type=ioemu"
-      elif instance.hvm_nic_type == constants.HT_HVM_DEV_PARAVIRTUAL:
-        nic_type = ", type=paravirtualized"
-      else:
-        nic_type = ", model=%s, type=ioemu" % instance.hvm_nic_type
-
-      nic_str = "mac=%s, bridge=%s%s" % (nic.mac, nic.bridge, nic_type)
+      nic_str = "mac=%s, bridge=%s%s" % (nic.mac, nic.bridge, nic_type_str)
       ip = getattr(nic, "ip", None)
       if ip is not None:
         nic_str += ", ip=%s" % ip
@@ -444,14 +540,15 @@ class XenHvmHypervisor(XenHypervisor):
     config.write("vif = [%s]\n" % ",".join(vif_data))
     disk_data = cls._GetConfigFileDiskData(instance.disk_template,
                                             block_devices)
-    if ((instance.hvm_disk_type is None) or
-        (instance.hvm_disk_type == constants.HT_HVM_DEV_IOEMU)):
+    disk_type = instance.hvparams[constants.HV_DISK_TYPE]
+    if disk_type in (None, constants.HT_HVM_DEV_IOEMU):
       replacement = ",ioemu:hd"
     else:
       replacement = ",hd"
     disk_data = [line.replace(",sd", replacement) for line in disk_data]
-    if instance.hvm_cdrom_image_path is not None:
-      iso = "'file:%s,hdc:cdrom,r'" % (instance.hvm_cdrom_image_path)
+    iso_path = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
+    if iso_path:
+      iso = "'file:%s,hdc:cdrom,r'" % iso_path
       disk_data.append(iso)
 
     config.write("disk = [%s]\n" % (",".join(disk_data)))