commit 35007011815c83ee244f85803f87c411f5bbe87d
Author: Iustin Pop <iustin@google.com>
Date:   Wed Jul 27 17:18:48 2011 +0200

    Remove requirement for variants on OS API v15+
    
    This removes:
    
    - the check in backend that such OSes have a variants file or if it
      exists that is non-empty; in order for this to work, we also rework
      the logic in backend._TryOSFromDisk to allow for optional OS files
    - the check in cluster verify such OSes to have a non-empty variant
      list (the check for consistent variants is still kept)
    
    Signed-off-by: Iustin Pop <iustin@google.com>
    Reviewed-by: Michael Hanselmann <hansmi@google.com>

diff --git a/lib/backend.py b/lib/backend.py
index d8b44e2..30fe8ff 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -2051,23 +2051,28 @@ def _TryOSFromDisk(name, base_dir=None):
     return False, ("API version mismatch for path '%s': found %s, want %s." %
                    (os_dir, api_versions, constants.OS_API_VERSIONS))
 
-  # OS Files dictionary, we will populate it with the absolute path names
-  os_files = dict.fromkeys(constants.OS_SCRIPTS)
+  # OS Files dictionary, we will populate it with the absolute path
+  # names; if the value is True, then it is a required file, otherwise
+  # an optional one
+  os_files = dict.fromkeys(constants.OS_SCRIPTS, True)
 
   if max(api_versions) >= constants.OS_API_V15:
-    os_files[constants.OS_VARIANTS_FILE] = ""
+    os_files[constants.OS_VARIANTS_FILE] = False
 
   if max(api_versions) >= constants.OS_API_V20:
-    os_files[constants.OS_PARAMETERS_FILE] = ""
+    os_files[constants.OS_PARAMETERS_FILE] = True
   else:
     del os_files[constants.OS_SCRIPT_VERIFY]
 
-  for filename in os_files:
+  for (filename, required) in os_files.items():
     os_files[filename] = utils.PathJoin(os_dir, filename)
 
     try:
       st = os.stat(os_files[filename])
     except EnvironmentError, err:
+      if err.errno == errno.ENOENT and not required:
+        del os_files[filename]
+        continue
       return False, ("File '%s' under path '%s' is missing (%s)" %
                      (filename, os_dir, _ErrnoOrStr(err)))
 
@@ -2086,10 +2091,10 @@ def _TryOSFromDisk(name, base_dir=None):
     try:
       variants = utils.ReadFile(variants_file).splitlines()
     except EnvironmentError, err:
-      return False, ("Error while reading the OS variants file at %s: %s" %
-                     (variants_file, _ErrnoOrStr(err)))
-    if not variants:
-      return False, ("No supported os variant found")
+      # we accept missing files, but not other errors
+      if err.errno != errno.ENOENT:
+        return False, ("Error while reading the OS variants file at %s: %s" %
+                       (variants_file, _ErrnoOrStr(err)))
 
   parameters = []
   if constants.OS_PARAMETERS_FILE in os_files:
@@ -2166,11 +2171,13 @@ def OSCoreEnv(os_name, inst_os, os_params, debug=0):
   result["DEBUG_LEVEL"] = "%d" % debug
 
   # OS variants
-  if api_version >= constants.OS_API_V15:
+  if api_version >= constants.OS_API_V15 and inst_os.supported_variants:
     variant = objects.OS.GetVariant(os_name)
     if not variant:
       variant = inst_os.supported_variants[0]
-    result["OS_VARIANT"] = variant
+  else:
+    variant = ""
+  result["OS_VARIANT"] = variant
 
   # OS params
   for pname, pvalue in os_params.items():
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 41ba0e4..6b880e7 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2193,11 +2193,6 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
       _ErrorIf(len(os_data) > 1, self.ENODEOS, node,
                "OS '%s' has multiple entries (first one shadows the rest): %s",
                os_name, utils.CommaJoin([v[0] for v in os_data]))
-      # this will catched in backend too
-      _ErrorIf(compat.any(v >= constants.OS_API_V15 for v in f_api)
-               and not f_var, self.ENODEOS, node,
-               "OS %s with API at least %d does not declare any variant",
-               os_name, constants.OS_API_V15)
       # comparisons with the 'base' image
       test = os_name not in base.oslist
       _ErrorIf(test, self.ENODEOS, node,
diff --git a/man/ganeti-os-interface.rst b/man/ganeti-os-interface.rst
index a8aff1f..4426766 100644
--- a/man/ganeti-os-interface.rst
+++ b/man/ganeti-os-interface.rst
@@ -255,9 +255,9 @@ one Ganeti version should contain the most recent version first
 variants.list
 ~~~~~~~~~~~~~
 
-variants.list is a plain text file containing all the declared
-supported variants for this OS, one per line. At least one variant
-must be supported.
+variants.list is a plain text file containing all the declared supported
+variants for this OS, one per line. If this file is missing or empty,
+then the OS won't be considered to support variants.
 
 parameters.list
 ~~~~~~~~~~~~~~~
@@ -308,8 +308,9 @@ Version 10 to 15
 
 The ``variants.list`` file has been added, so OSes should support at
 least one variant, declaring it in that file and must be prepared to
-parse the OS_VARIANT environment variable. OSes are free to support
-more variants than just the declared ones.
+parse the OS_VARIANT environment variable. OSes are free to support more
+variants than just the declared ones. Note that this file is optional;
+without it, the variants functionality is disabled.
 
 Version 5 to 10
 ^^^^^^^^^^^^^^^
