Make invocation of rapi test configurable by QA config
[ganeti-local] / qa / qa_os.py
index 143fedc..f96e27e 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2007, 2008, 2009, 2010 Google Inc.
+# Copyright (C) 2007, 2008, 2009, 2010, 2011 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -28,148 +28,196 @@ import os.path
 
 from ganeti import utils
 from ganeti import constants
+from ganeti import pathutils
 
 import qa_config
 import qa_utils
+import qa_error
 
-from qa_utils import AssertEqual, StartSSH
+from qa_utils import AssertCommand, AssertIn, AssertNotIn
 
 
 _TEMP_OS_NAME = "TEMP-Ganeti-QA-OS"
-_TEMP_OS_PATH = os.path.join(constants.OS_SEARCH_PATH[0], _TEMP_OS_NAME)
+_TEMP_OS_PATH = os.path.join(pathutils.OS_SEARCH_PATH[0], _TEMP_OS_NAME)
+
+(_ALL_VALID,
+ _ALL_INVALID,
+ _PARTIALLY_VALID) = range(1, 4)
 
 
 def TestOsList():
   """gnt-os list"""
-  master = qa_config.GetMasterNode()
-
-  cmd = ['gnt-os', 'list']
-  AssertEqual(StartSSH(master['primary'],
-                       utils.ShellQuoteArgs(cmd)).wait(), 0)
+  AssertCommand(["gnt-os", "list"])
 
 
 def TestOsDiagnose():
   """gnt-os diagnose"""
-  master = qa_config.GetMasterNode()
-
-  cmd = ['gnt-os', 'diagnose']
-  AssertEqual(StartSSH(master['primary'],
-                       utils.ShellQuoteArgs(cmd)).wait(), 0)
+  AssertCommand(["gnt-os", "diagnose"])
 
 
-def _TestOsModify(hvp_dict, expected_result=0):
+def _TestOsModify(hvp_dict, fail=False):
   """gnt-os modify"""
-  master = qa_config.GetMasterNode()
-
-  cmd = ['gnt-os', 'modify']
+  cmd = ["gnt-os", "modify"]
 
   for hv_name, hv_params in hvp_dict.items():
-    cmd.append('-H')
+    cmd.append("-H")
     options = []
     for key, value in hv_params.items():
       options.append("%s=%s" % (key, value))
-    cmd.append('%s:%s' % (hv_name, ','.join(options)))
+    cmd.append("%s:%s" % (hv_name, ",".join(options)))
 
   cmd.append(_TEMP_OS_NAME)
-  AssertEqual(StartSSH(master['primary'],
-                       utils.ShellQuoteArgs(cmd)).wait(), expected_result)
+  AssertCommand(cmd, fail=fail)
 
 
-def _TestOsStates():
+def _TestOsStates(os_name):
   """gnt-os modify, more stuff"""
-  master = qa_config.GetMasterNode()
-
   cmd = ["gnt-os", "modify"]
 
   for param in ["hidden", "blacklisted"]:
     for val in ["yes", "no"]:
-      new_cmd = cmd + ["--%s" % param, val, _TEMP_OS_NAME]
-      AssertEqual(StartSSH(master["primary"],
-                           utils.ShellQuoteArgs(new_cmd)).wait(), 0)
+      new_cmd = cmd + ["--%s" % param, val, os_name]
+      AssertCommand(new_cmd)
+      # check that double-running the command is OK
+      AssertCommand(new_cmd)
 
 
-def _SetupTempOs(node, dir, valid):
+def _SetupTempOs(node, dirname, variant, valid):
   """Creates a temporary OS definition on the given node.
 
   """
   sq = utils.ShellQuoteArgs
-  parts = [sq(["rm", "-rf", dir]),
-           sq(["mkdir", "-p", dir]),
-           sq(["cd", dir]),
-           sq(["ln", "-fs", "/bin/true", "export"]),
-           sq(["ln", "-fs", "/bin/true", "import"]),
-           sq(["ln", "-fs", "/bin/true", "rename"])]
+  parts = [
+    sq(["rm", "-rf", dirname]),
+    sq(["mkdir", "-p", dirname]),
+    sq(["cd", dirname]),
+    sq(["ln", "-fs", "/bin/true", "export"]),
+    sq(["ln", "-fs", "/bin/true", "import"]),
+    sq(["ln", "-fs", "/bin/true", "rename"]),
+    sq(["ln", "-fs", "/bin/true", "verify"]),
+    ]
 
   if valid:
     parts.append(sq(["ln", "-fs", "/bin/true", "create"]))
 
-  parts.append(sq(["echo", str(constants.OS_API_V10)]) +
+  parts.append(sq(["echo", str(constants.OS_API_V20)]) +
                " >ganeti_api_version")
 
-  cmd = ' && '.join(parts)
+  parts.append(sq(["echo", variant]) + " >variants.list")
+  parts.append(sq(["echo", "funny this is funny"]) + " >parameters.list")
+
+  cmd = " && ".join(parts)
 
   print qa_utils.FormatInfo("Setting up %s with %s OS definition" %
-                            (node["primary"],
+                            (node.primary,
                              ["an invalid", "a valid"][int(valid)]))
 
-  AssertEqual(StartSSH(node['primary'], cmd).wait(), 0)
+  AssertCommand(cmd, node=node)
 
 
-def _RemoveTempOs(node, dir):
+def _RemoveTempOs(node, dirname):
   """Removes a temporary OS definition.
 
   """
-  cmd = ['rm', '-rf', dir]
-  AssertEqual(StartSSH(node['primary'],
-                       utils.ShellQuoteArgs(cmd)).wait(), 0)
+  AssertCommand(["rm", "-rf", dirname], node=node)
 
 
-def _TestOs(mode):
+def _TestOs(mode, rapi_cb):
   """Generic function for OS definition testing
 
   """
   master = qa_config.GetMasterNode()
-  dir = _TEMP_OS_PATH
+
+  name = _TEMP_OS_NAME
+  variant = "default"
+  fullname = "%s+%s" % (name, variant)
+  dirname = _TEMP_OS_PATH
+
+  # Ensure OS is usable
+  cmd = ["gnt-os", "modify", "--hidden=no", "--blacklisted=no", name]
+  AssertCommand(cmd)
 
   nodes = []
   try:
-    i = 0
-    for node in qa_config.get('nodes'):
+    for i, node in enumerate(qa_config.get("nodes")):
       nodes.append(node)
-      if mode == 0:
+      if mode == _ALL_INVALID:
         valid = False
-      elif mode == 1:
+      elif mode == _ALL_VALID:
         valid = True
-      else:
+      elif mode == _PARTIALLY_VALID:
         valid = bool(i % 2)
-      _SetupTempOs(node, dir, valid)
-      i += 1
-
-    cmd = ['gnt-os', 'diagnose']
-    result = StartSSH(master['primary'],
-                      utils.ShellQuoteArgs(cmd)).wait()
-    if mode == 1:
-      AssertEqual(result, 0)
-    else:
-      AssertEqual(result, 1)
+      else:
+        raise AssertionError("Unknown mode %s" % mode)
+      _SetupTempOs(node, dirname, variant, valid)
+
+    # TODO: Use Python 2.6's itertools.permutations
+    for (hidden, blacklisted) in [(False, False), (True, False),
+                                  (False, True), (True, True)]:
+      # Change OS' visibility
+      cmd = ["gnt-os", "modify", "--hidden", ["no", "yes"][int(hidden)],
+             "--blacklisted", ["no", "yes"][int(blacklisted)], name]
+      AssertCommand(cmd)
+
+      # Diagnose, checking exit status
+      AssertCommand(["gnt-os", "diagnose"], fail=(mode != _ALL_VALID))
+
+      # Diagnose again, ignoring exit status
+      output = qa_utils.GetCommandOutput(master.primary,
+                                         "gnt-os diagnose || :")
+      for line in output.splitlines():
+        if line.startswith("OS: %s [global status:" % name):
+          break
+      else:
+        raise qa_error.Error("Didn't find OS '%s' in 'gnt-os diagnose'" % name)
+
+      # Check info for all
+      cmd = ["gnt-os", "info"]
+      output = qa_utils.GetCommandOutput(master.primary,
+                                         utils.ShellQuoteArgs(cmd))
+      AssertIn("%s:" % name, output.splitlines())
+
+      # Check info for OS
+      cmd = ["gnt-os", "info", name]
+      output = qa_utils.GetCommandOutput(master.primary,
+                                         utils.ShellQuoteArgs(cmd)).splitlines()
+      AssertIn("%s:" % name, output)
+      for (field, value) in [("valid", mode == _ALL_VALID),
+                             ("hidden", hidden),
+                             ("blacklisted", blacklisted)]:
+        AssertIn("  - %s: %s" % (field, value), output)
+
+      # Only valid OSes should be listed
+      cmd = ["gnt-os", "list", "--no-headers"]
+      output = qa_utils.GetCommandOutput(master.primary,
+                                         utils.ShellQuoteArgs(cmd))
+      if mode == _ALL_VALID and not (hidden or blacklisted):
+        assert_fn = AssertIn
+      else:
+        assert_fn = AssertNotIn
+      assert_fn(fullname, output.splitlines())
+
+      # Check via RAPI
+      if rapi_cb:
+        assert_fn(fullname, rapi_cb())
   finally:
     for node in nodes:
-      _RemoveTempOs(node, dir)
+      _RemoveTempOs(node, dirname)
 
 
-def TestOsValid():
+def TestOsValid(rapi_cb):
   """Testing valid OS definition"""
-  return _TestOs(1)
+  return _TestOs(_ALL_VALID, rapi_cb)
 
 
-def TestOsInvalid():
+def TestOsInvalid(rapi_cb):
   """Testing invalid OS definition"""
-  return _TestOs(0)
+  return _TestOs(_ALL_INVALID, rapi_cb)
 
 
-def TestOsPartiallyValid():
+def TestOsPartiallyValid(rapi_cb):
   """Testing partially valid OS definition"""
-  return _TestOs(2)
+  return _TestOs(_PARTIALLY_VALID, rapi_cb)
 
 
 def TestOsModifyValid():
@@ -193,10 +241,10 @@ def TestOsModifyInvalid():
     "blahblahblubb": {"bar": ""},
     }
 
-  return _TestOsModify(hv_dict, 1)
-
+  return _TestOsModify(hv_dict, fail=True)
 
-def TestOsStates():
-  """Testing OS states"""
 
-  return _TestOsStates()
+def TestOsStatesNonExisting():
+  """Testing OS states with non-existing OS"""
+  AssertCommand(["test", "-e", _TEMP_OS_PATH], fail=True)
+  return _TestOsStates(_TEMP_OS_NAME)