hypervisors: add hvparams to GetNodeInfo
[ganeti-local] / lib / ssconf.py
index 7e34b5d..11af2a2 100644 (file)
@@ -30,6 +30,7 @@ import sys
 import errno
 import logging
 
+from ganeti import compat
 from ganeti import errors
 from ganeti import constants
 from ganeti import utils
@@ -40,7 +41,7 @@ from ganeti import pathutils
 SSCONF_LOCK_TIMEOUT = 10
 
 #: Valid ssconf keys
-_VALID_KEYS = frozenset([
+_VALID_KEYS = compat.UniqueFrozenset([
   constants.SS_CLUSTER_NAME,
   constants.SS_CLUSTER_TAGS,
   constants.SS_FILE_STORAGE_DIR,
@@ -64,6 +65,12 @@ _VALID_KEYS = frozenset([
   constants.SS_UID_POOL,
   constants.SS_NODEGROUPS,
   constants.SS_NETWORKS,
+  constants.SS_HVPARAMS_XEN_PVM,
+  constants.SS_HVPARAMS_XEN_FAKE,
+  constants.SS_HVPARAMS_XEN_HVM,
+  constants.SS_HVPARAMS_XEN_KVM,
+  constants.SS_HVPARAMS_XEN_CHROOT,
+  constants.SS_HVPARAMS_XEN_LXC,
   ])
 
 #: Maximum size for ssconf files
@@ -103,12 +110,14 @@ class SimpleStore(object):
     - keys are restricted to predefined values
 
   """
-  def __init__(self, cfg_location=None):
+  def __init__(self, cfg_location=None, _lockfile=pathutils.SSCONF_LOCK_FILE):
     if cfg_location is None:
       self._cfg_dir = pathutils.DATA_DIR
     else:
       self._cfg_dir = cfg_location
 
+    self._lockfile = _lockfile
+
   def KeyToFilename(self, key):
     """Convert a given key into filename.
 
@@ -136,14 +145,36 @@ class SimpleStore(object):
       raise errors.ConfigurationError("Can't read ssconf file %s: %s" %
                                       (filename, str(err)))
 
-  def WriteFiles(self, values):
+  def ReadAll(self):
+    """Reads all keys and returns their values.
+
+    @rtype: dict
+    @return: Dictionary, ssconf key as key, value as value
+
+    """
+    result = []
+
+    for key in _VALID_KEYS:
+      try:
+        value = self._ReadFile(key)
+      except errors.ConfigurationError:
+        # Ignore non-existing files
+        pass
+      else:
+        result.append((key, value))
+
+    return dict(result)
+
+  def WriteFiles(self, values, dry_run=False):
     """Writes ssconf files used by external scripts.
 
     @type values: dict
     @param values: Dictionary of (name, value)
+    @type dry_run boolean
+    @param dry_run: Whether to perform a dry run
 
     """
-    ssconf_lock = utils.FileLock.Open(pathutils.SSCONF_LOCK_FILE)
+    ssconf_lock = utils.FileLock.Open(self._lockfile)
 
     # Get lock while writing files
     ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
@@ -151,11 +182,15 @@ class SimpleStore(object):
       for name, value in values.iteritems():
         if value and not value.endswith("\n"):
           value += "\n"
+
         if len(value) > _MAX_SIZE:
-          raise errors.ConfigurationError("ssconf file %s above maximum size" %
-                                          name)
+          msg = ("Value '%s' has a length of %s bytes, but only up to %s are"
+                 " allowed" % (name, len(value), _MAX_SIZE))
+          raise errors.ConfigurationError(msg)
+
         utils.WriteFile(self.KeyToFilename(name), data=value,
-                        mode=constants.SS_FILE_PERMS)
+                        mode=constants.SS_FILE_PERMS,
+                        dry_run=dry_run)
     finally:
       ssconf_lock.Unlock()
 
@@ -286,6 +321,35 @@ class SimpleStore(object):
     nl = data.splitlines(False)
     return nl
 
+  def GetHvparamsForHypervisor(self, hvname):
+    """Return the hypervisor parameters of the given hypervisor.
+
+    @type hvname: string
+    @param hvname: name of the hypervisor, must be in C{constants.HYPER_TYPES}
+    @rtype: dict of strings
+    @returns: dictionary with hypervisor parameters
+
+    """
+    data = self._ReadFile(constants.SS_HVPARAMS_PREF + hvname)
+    lines = data.splitlines(False)
+    hvparams = {}
+    for line in lines:
+      (key, value) = line.split("=")
+      hvparams[key] = value
+    return hvparams
+
+  def GetHvparams(self):
+    """Return the hypervisor parameters of all hypervisors.
+
+    @rtype: dict of dict of strings
+    @returns: dictionary mapping hypervisor names to hvparams
+
+    """
+    all_hvparams = {}
+    for hv in constants.HYPER_TYPES:
+      all_hvparams[hv] = self.GetHvparamsForHypervisor(hv)
+    return all_hvparams
+
   def GetMaintainNodeHealth(self):
     """Return the value of the maintain_node_health option.
 
@@ -320,13 +384,13 @@ class SimpleStore(object):
                                       " family: %s" % err)
 
 
-def WriteSsconfFiles(values):
+def WriteSsconfFiles(values, dry_run=False):
   """Update all ssconf files.
 
   Wrapper around L{SimpleStore.WriteFiles}.
 
   """
-  SimpleStore().WriteFiles(values)
+  SimpleStore().WriteFiles(values, dry_run=dry_run)
 
 
 def GetMasterAndMyself(ss=None):
@@ -387,3 +451,17 @@ def VerifyClusterName(name, _cfg_location=None):
   else:
     if name != local_name:
       raise errors.GenericError("Current cluster name is '%s'" % local_name)
+
+
+def VerifyKeys(keys):
+  """Raises an exception if unknown ssconf keys are given.
+
+  @type keys: sequence
+  @param keys: Key names to verify
+  @raise errors.GenericError: When invalid keys were found
+
+  """
+  invalid = frozenset(keys) - _VALID_KEYS
+  if invalid:
+    raise errors.GenericError("Invalid ssconf keys: %s" %
+                              utils.CommaJoin(sorted(invalid)))