QA: Cluster-verify reports shared PVs with exclusive storage
[ganeti-local] / qa / qa_instance.py
index aefae7e..b604d97 100644 (file)
@@ -86,16 +86,15 @@ def _DiskTest(node, disk_template):
 def _GetInstanceInfo(instance):
   """Return information about the actual state of an instance.
 
 def _GetInstanceInfo(instance):
   """Return information about the actual state of an instance.
 
-  The pieces of information returned are:
-    - "nodes": instance nodes, a list of strings
-    - "volumes": instance volume IDs, a list of strings
-  @type instance: dictionary
-  @param instance: the instance
-  @return: dictionary
+  @type instance: string
+  @param instance: the instance name
+  @return: a dictionary with two keys:
+      - "nodes": instance nodes, a list of strings
+      - "volumes": instance volume IDs, a list of strings
 
   """
   master = qa_config.GetMasterNode()
 
   """
   master = qa_config.GetMasterNode()
-  infocmd = utils.ShellQuoteArgs(["gnt-instance", "info", instance["name"]])
+  infocmd = utils.ShellQuoteArgs(["gnt-instance", "info", instance])
   info_out = qa_utils.GetCommandOutput(master["primary"], infocmd)
   re_node = re.compile(r"^\s+-\s+(?:primary|secondaries):\s+(\S.+)$")
   node_elem = r"([^,()]+)(?:\s+\([^)]+\))?"
   info_out = qa_utils.GetCommandOutput(master["primary"], infocmd)
   re_node = re.compile(r"^\s+-\s+(?:primary|secondaries):\s+(\S.+)$")
   node_elem = r"([^,()]+)(?:\s+\([^)]+\))?"
@@ -134,7 +133,7 @@ def _DestroyInstanceVolumes(instance):
   @param instance: the instance
 
   """
   @param instance: the instance
 
   """
-  info = _GetInstanceInfo(instance)
+  info = _GetInstanceInfo(instance["name"])
   vols = info["volumes"]
   for node in info["nodes"]:
     AssertCommand(["lvremove", "-f"] + vols, node=node)
   vols = info["volumes"]
   for node in info["nodes"]:
     AssertCommand(["lvremove", "-f"] + vols, node=node)
@@ -270,17 +269,35 @@ def TestInstanceRenameAndBack(rename_source, rename_target):
   finally:
     qa_utils.RemoveFromEtcHosts(["meeeeh-not-exists", rename_target])
 
   finally:
     qa_utils.RemoveFromEtcHosts(["meeeeh-not-exists", rename_target])
 
+  # Check instance volume tags correctly updated
+  # FIXME: this is LVM specific!
+  info = _GetInstanceInfo(rename_source)
+  tags_cmd = ("lvs -o tags --noheadings %s | grep " %
+              (" ".join(info["volumes"]), ))
+
   # and now rename instance to rename_target...
   AssertCommand(["gnt-instance", "rename", rename_source, rename_target])
   _CheckSsconfInstanceList(rename_target)
   qa_utils.RunInstanceCheck(rename_source, False)
   qa_utils.RunInstanceCheck(rename_target, False)
 
   # and now rename instance to rename_target...
   AssertCommand(["gnt-instance", "rename", rename_source, rename_target])
   _CheckSsconfInstanceList(rename_target)
   qa_utils.RunInstanceCheck(rename_source, False)
   qa_utils.RunInstanceCheck(rename_target, False)
 
+  # NOTE: tags might not be the exactly as the instance name, due to
+  # charset restrictions; hence the test might be flaky
+  if rename_source != rename_target:
+    for node in info["nodes"]:
+      AssertCommand(tags_cmd + rename_source, node=node, fail=True)
+      AssertCommand(tags_cmd + rename_target, node=node, fail=False)
+
   # and back
   AssertCommand(["gnt-instance", "rename", rename_target, rename_source])
   _CheckSsconfInstanceList(rename_source)
   qa_utils.RunInstanceCheck(rename_target, False)
 
   # and back
   AssertCommand(["gnt-instance", "rename", rename_target, rename_source])
   _CheckSsconfInstanceList(rename_source)
   qa_utils.RunInstanceCheck(rename_target, False)
 
+  if rename_source != rename_target:
+    for node in info["nodes"]:
+      AssertCommand(tags_cmd + rename_source, node=node, fail=False)
+      AssertCommand(tags_cmd + rename_target, node=node, fail=True)
+
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestInstanceFailover(instance):
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestInstanceFailover(instance):
@@ -405,9 +422,12 @@ def TestInstanceModify(instance):
   # check no-modify
   AssertCommand(["gnt-instance", "modify", instance["name"]], fail=True)
 
   # check no-modify
   AssertCommand(["gnt-instance", "modify", instance["name"]], fail=True)
 
-  # Marking offline/online while instance is running must fail
-  for arg in ["--online", "--offline"]:
-    AssertCommand(["gnt-instance", "modify", arg, instance["name"]], fail=True)
+  # Marking offline while instance is running must fail...
+  AssertCommand(["gnt-instance", "modify", "--offline", instance["name"]],
+                 fail=True)
+
+  # ...while making it online is ok, and should work
+  AssertCommand(["gnt-instance", "modify", "--online", instance["name"]])
 
 
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
 
 
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
@@ -421,6 +441,16 @@ def TestInstanceStoppedModify(instance):
   # Mark instance as offline
   AssertCommand(["gnt-instance", "modify", "--offline", name])
 
   # Mark instance as offline
   AssertCommand(["gnt-instance", "modify", "--offline", name])
 
+  # When the instance is offline shutdown should only work with --force,
+  # while start should never work
+  AssertCommand(["gnt-instance", "shutdown", name], fail=True)
+  AssertCommand(["gnt-instance", "shutdown", "--force", name])
+  AssertCommand(["gnt-instance", "start", name], fail=True)
+  AssertCommand(["gnt-instance", "start", "--force", name], fail=True)
+
+  # Also do offline to offline
+  AssertCommand(["gnt-instance", "modify", "--offline", name])
+
   # And online again
   AssertCommand(["gnt-instance", "modify", "--online", name])
 
   # And online again
   AssertCommand(["gnt-instance", "modify", "--online", name])
 
@@ -485,19 +515,23 @@ def TestReplaceDisks(instance, pnode, snode, othernode):
     cmd.append(instance["name"])
     return cmd
 
     cmd.append(instance["name"])
     return cmd
 
+  options = qa_config.get("options", {})
+  use_ialloc = options.get("use-iallocators", True)
   for data in [
     ["-p"],
     ["-s"],
   for data in [
     ["-p"],
     ["-s"],
-    ["--new-secondary=%s" % othernode["primary"]],
-    ["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT],
+    # A placeholder; the actual command choice depends on use_ialloc
+    None,
+    # Restore the original secondary
+    ["--new-secondary=%s" % snode["primary"]],
     ]:
     ]:
+    if data is None:
+      if use_ialloc:
+        data = ["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT]
+      else:
+        data = ["--new-secondary=%s" % othernode["primary"]]
     AssertCommand(buildcmd(data))
 
     AssertCommand(buildcmd(data))
 
-  # Restore the original secondary, if needed
-  currsec = _GetInstanceInfo(instance)["nodes"][1]
-  if currsec != snode["primary"]:
-    AssertCommand(buildcmd(["--new-secondary=%s" % snode["primary"]]))
-
   AssertCommand(buildcmd(["-a"]))
   AssertCommand(["gnt-instance", "stop", instance["name"]])
   AssertCommand(buildcmd(["-a"]), fail=True)
   AssertCommand(buildcmd(["-a"]))
   AssertCommand(["gnt-instance", "stop", instance["name"]])
   AssertCommand(buildcmd(["-a"]), fail=True)
@@ -541,22 +575,31 @@ def TestRecreateDisks(instance, pnode, snode, othernodes):
   @param othernodes: list/tuple of nodes where to temporarily recreate disks
 
   """
   @param othernodes: list/tuple of nodes where to temporarily recreate disks
 
   """
+  options = qa_config.get("options", {})
+  use_ialloc = options.get("use-iallocators", True)
   other_seq = ":".join([n["primary"] for n in othernodes])
   orig_seq = pnode["primary"]
   if snode:
     orig_seq = orig_seq + ":" + snode["primary"]
   # These fail because the instance is running
   _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
   other_seq = ":".join([n["primary"] for n in othernodes])
   orig_seq = pnode["primary"]
   if snode:
     orig_seq = orig_seq + ":" + snode["primary"]
   # These fail because the instance is running
   _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
-  _AssertRecreateDisks(["-I", "hail"], instance, fail=True, destroy=False)
+  if use_ialloc:
+    _AssertRecreateDisks(["-I", "hail"], instance, fail=True, destroy=False)
+  else:
+    _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
   AssertCommand(["gnt-instance", "stop", instance["name"]])
   # Disks exist: this should fail
   _AssertRecreateDisks([], instance, fail=True, destroy=False)
   # Recreate disks in place
   _AssertRecreateDisks([], instance)
   # Move disks away
   AssertCommand(["gnt-instance", "stop", instance["name"]])
   # Disks exist: this should fail
   _AssertRecreateDisks([], instance, fail=True, destroy=False)
   # Recreate disks in place
   _AssertRecreateDisks([], instance)
   # Move disks away
-  _AssertRecreateDisks(["-I", "hail"], instance)
-  # Move disks somewhere else
-  _AssertRecreateDisks(["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT], instance)
+  if use_ialloc:
+    _AssertRecreateDisks(["-I", "hail"], instance)
+    # Move disks somewhere else
+    _AssertRecreateDisks(["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT],
+                         instance)
+  else:
+    _AssertRecreateDisks(["-n", other_seq], instance)
   # Move disks back
   _AssertRecreateDisks(["-n", orig_seq], instance, check=False)
   # This and InstanceCheck decoration check that the disks are working
   # Move disks back
   _AssertRecreateDisks(["-n", orig_seq], instance, check=False)
   # This and InstanceCheck decoration check that the disks are working