qa_utils: Support virtual cluster for backup files
[ganeti-local] / qa / qa_rapi.py
index df040e3..887f3b7 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
 #
 #
 
-# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 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
 #
 # 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
@@ -37,6 +37,7 @@ from ganeti import objects
 from ganeti import query
 from ganeti import compat
 from ganeti import qlang
 from ganeti import query
 from ganeti import compat
 from ganeti import qlang
+from ganeti import pathutils
 
 import ganeti.rapi.client        # pylint: disable=W0611
 import ganeti.rapi.client_utils
 
 import ganeti.rapi.client        # pylint: disable=W0611
 import ganeti.rapi.client_utils
@@ -45,6 +46,9 @@ import qa_config
 import qa_utils
 import qa_error
 
 import qa_utils
 import qa_error
 
+from qa_instance import IsFailoverSupported
+from qa_instance import IsMigrationSupported
+from qa_instance import IsDiskReplacingSupported
 from qa_utils import (AssertEqual, AssertIn, AssertMatch, StartLocalCommand)
 from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG
 
 from qa_utils import (AssertEqual, AssertIn, AssertMatch, StartLocalCommand)
 from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG
 
@@ -72,11 +76,11 @@ def Setup(username, password):
   master = qa_config.GetMasterNode()
 
   # Load RAPI certificate from master node
   master = qa_config.GetMasterNode()
 
   # Load RAPI certificate from master node
-  cmd = ["cat", constants.RAPI_CERT_FILE]
+  cmd = ["cat", pathutils.RAPI_CERT_FILE]
 
   # Write to temporary file
   _rapi_ca = tempfile.NamedTemporaryFile()
 
   # Write to temporary file
   _rapi_ca = tempfile.NamedTemporaryFile()
-  _rapi_ca.write(qa_utils.GetCommandOutput(master["primary"],
+  _rapi_ca.write(qa_utils.GetCommandOutput(master.primary,
                                            utils.ShellQuoteArgs(cmd)))
   _rapi_ca.flush()
 
                                            utils.ShellQuoteArgs(cmd)))
   _rapi_ca.flush()
 
@@ -84,7 +88,7 @@ def Setup(username, password):
   cfg_curl = rapi.client.GenericCurlConfig(cafile=_rapi_ca.name,
                                            proxy="")
 
   cfg_curl = rapi.client.GenericCurlConfig(cafile=_rapi_ca.name,
                                            proxy="")
 
-  _rapi_client = rapi.client.GanetiRapiClient(master["primary"], port=port,
+  _rapi_client = rapi.client.GanetiRapiClient(master.primary, port=port,
                                               username=username,
                                               password=password,
                                               curl_config_fn=cfg_curl)
                                               username=username,
                                               password=password,
                                               curl_config_fn=cfg_curl)
@@ -103,13 +107,13 @@ NODE_FIELDS = ("name", "dtotal", "dfree",
                "mtotal", "mnode", "mfree",
                "pinst_cnt", "sinst_cnt", "tags")
 
                "mtotal", "mnode", "mfree",
                "pinst_cnt", "sinst_cnt", "tags")
 
-GROUP_FIELDS = frozenset([
+GROUP_FIELDS = compat.UniqueFrozenset([
   "name", "uuid",
   "alloc_policy",
   "node_cnt", "node_list",
   ])
 
   "name", "uuid",
   "alloc_policy",
   "node_cnt", "node_list",
   ])
 
-JOB_FIELDS = frozenset([
+JOB_FIELDS = compat.UniqueFrozenset([
   "id", "ops", "status", "summary",
   "opstatus", "opresult", "oplog",
   "received_ts", "start_ts", "end_ts",
   "id", "ops", "status", "summary",
   "opstatus", "opresult", "oplog",
   "received_ts", "start_ts", "end_ts",
@@ -373,19 +377,19 @@ def TestInstance(instance):
       _VerifyInstance(instance_data)
 
   _DoTests([
       _VerifyInstance(instance_data)
 
   _DoTests([
-    ("/2/instances/%s" % instance["name"], _VerifyInstance, "GET", None),
+    ("/2/instances/%s" % instance.name, _VerifyInstance, "GET", None),
     ("/2/instances", _VerifyInstancesList, "GET", None),
     ("/2/instances?bulk=1", _VerifyInstancesBulk, "GET", None),
     ("/2/instances", _VerifyInstancesList, "GET", None),
     ("/2/instances?bulk=1", _VerifyInstancesBulk, "GET", None),
-    ("/2/instances/%s/activate-disks" % instance["name"],
+    ("/2/instances/%s/activate-disks" % instance.name,
      _VerifyReturnsJob, "PUT", None),
      _VerifyReturnsJob, "PUT", None),
-    ("/2/instances/%s/deactivate-disks" % instance["name"],
+    ("/2/instances/%s/deactivate-disks" % instance.name,
      _VerifyReturnsJob, "PUT", None),
     ])
 
   # Test OpBackupPrepare
   (job_id, ) = _DoTests([
     ("/2/instances/%s/prepare-export?mode=%s" %
      _VerifyReturnsJob, "PUT", None),
     ])
 
   # Test OpBackupPrepare
   (job_id, ) = _DoTests([
     ("/2/instances/%s/prepare-export?mode=%s" %
-     (instance["name"], constants.EXPORT_MODE_REMOTE),
+     (instance.name, constants.EXPORT_MODE_REMOTE),
      _VerifyReturnsJob, "PUT", None),
     ])
 
      _VerifyReturnsJob, "PUT", None),
     ])
 
@@ -414,7 +418,7 @@ def TestNode(node):
       _VerifyNode(node_data)
 
   _DoTests([
       _VerifyNode(node_data)
 
   _DoTests([
-    ("/2/nodes/%s" % node["primary"], _VerifyNode, "GET", None),
+    ("/2/nodes/%s" % node.primary, _VerifyNode, "GET", None),
     ("/2/nodes", _VerifyNodesList, "GET", None),
     ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None),
     ])
     ("/2/nodes", _VerifyNodesList, "GET", None),
     ("/2/nodes?bulk=1", _VerifyNodesBulk, "GET", None),
     ])
@@ -491,9 +495,7 @@ def TestRapiNodeGroups():
   """Test several node group operations using RAPI.
 
   """
   """Test several node group operations using RAPI.
 
   """
-  groups = qa_config.get("groups", {})
-  group1, group2, group3 = groups.get("inexistent-groups",
-                                      ["group1", "group2", "group3"])[:3]
+  (group1, group2, group3) = qa_utils.GetNonexistentGroups(3)
 
   # Create a group with no attributes
   body = {
 
   # Create a group with no attributes
   body = {
@@ -552,11 +554,11 @@ def TestRapiNodeGroups():
 def TestRapiInstanceAdd(node, use_client):
   """Test adding a new instance via RAPI"""
   instance = qa_config.AcquireInstance()
 def TestRapiInstanceAdd(node, use_client):
   """Test adding a new instance via RAPI"""
   instance = qa_config.AcquireInstance()
+  instance.SetDiskTemplate(constants.DT_PLAIN)
   try:
     disk_sizes = [utils.ParseUnit(size) for size in qa_config.get("disk")]
     disks = [{"size": size} for size in disk_sizes]
   try:
     disk_sizes = [utils.ParseUnit(size) for size in qa_config.get("disk")]
     disks = [{"size": size} for size in disk_sizes]
-    nic0_mac = qa_config.GetInstanceNicMac(instance,
-                                           default=constants.VALUE_GENERATE)
+    nic0_mac = instance.GetNicMacAddr(0, constants.VALUE_GENERATE)
     nics = [{
       constants.INIC_MAC: nic0_mac,
       }]
     nics = [{
       constants.INIC_MAC: nic0_mac,
       }]
@@ -568,20 +570,20 @@ def TestRapiInstanceAdd(node, use_client):
 
     if use_client:
       job_id = _rapi_client.CreateInstance(constants.INSTANCE_CREATE,
 
     if use_client:
       job_id = _rapi_client.CreateInstance(constants.INSTANCE_CREATE,
-                                           instance["name"],
+                                           instance.name,
                                            constants.DT_PLAIN,
                                            disks, nics,
                                            os=qa_config.get("os"),
                                            constants.DT_PLAIN,
                                            disks, nics,
                                            os=qa_config.get("os"),
-                                           pnode=node["primary"],
+                                           pnode=node.primary,
                                            beparams=beparams)
     else:
       body = {
         "__version__": 1,
         "mode": constants.INSTANCE_CREATE,
                                            beparams=beparams)
     else:
       body = {
         "__version__": 1,
         "mode": constants.INSTANCE_CREATE,
-        "name": instance["name"],
+        "name": instance.name,
         "os_type": qa_config.get("os"),
         "disk_template": constants.DT_PLAIN,
         "os_type": qa_config.get("os"),
         "disk_template": constants.DT_PLAIN,
-        "pnode": node["primary"],
+        "pnode": node.primary,
         "beparams": beparams,
         "disks": disks,
         "nics": nics,
         "beparams": beparams,
         "disks": disks,
         "nics": nics,
@@ -595,7 +597,7 @@ def TestRapiInstanceAdd(node, use_client):
 
     return instance
   except:
 
     return instance
   except:
-    qa_config.ReleaseInstance(instance)
+    instance.Release()
     raise
 
 
     raise
 
 
@@ -603,47 +605,53 @@ def TestRapiInstanceAdd(node, use_client):
 def TestRapiInstanceRemove(instance, use_client):
   """Test removing instance via RAPI"""
   if use_client:
 def TestRapiInstanceRemove(instance, use_client):
   """Test removing instance via RAPI"""
   if use_client:
-    job_id = _rapi_client.DeleteInstance(instance["name"])
+    job_id = _rapi_client.DeleteInstance(instance.name)
   else:
     (job_id, ) = _DoTests([
   else:
     (job_id, ) = _DoTests([
-      ("/2/instances/%s" % instance["name"], _VerifyReturnsJob, "DELETE", None),
+      ("/2/instances/%s" % instance.name, _VerifyReturnsJob, "DELETE", None),
       ])
 
   _WaitForRapiJob(job_id)
 
       ])
 
   _WaitForRapiJob(job_id)
 
-  qa_config.ReleaseInstance(instance)
-
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceMigrate(instance):
   """Test migrating instance via RAPI"""
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceMigrate(instance):
   """Test migrating instance via RAPI"""
+  if not IsMigrationSupported(instance):
+    print qa_utils.FormatInfo("Instance doesn't support migration, skipping"
+                              " test")
+    return
   # Move to secondary node
   # Move to secondary node
-  _WaitForRapiJob(_rapi_client.MigrateInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.MigrateInstance(instance.name))
   qa_utils.RunInstanceCheck(instance, True)
   # And back to previous primary
   qa_utils.RunInstanceCheck(instance, True)
   # And back to previous primary
-  _WaitForRapiJob(_rapi_client.MigrateInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.MigrateInstance(instance.name))
 
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceFailover(instance):
   """Test failing over instance via RAPI"""
 
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceFailover(instance):
   """Test failing over instance via RAPI"""
+  if not IsFailoverSupported(instance):
+    print qa_utils.FormatInfo("Instance doesn't support failover, skipping"
+                              " test")
+    return
   # Move to secondary node
   # Move to secondary node
-  _WaitForRapiJob(_rapi_client.FailoverInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.FailoverInstance(instance.name))
   qa_utils.RunInstanceCheck(instance, True)
   # And back to previous primary
   qa_utils.RunInstanceCheck(instance, True)
   # And back to previous primary
-  _WaitForRapiJob(_rapi_client.FailoverInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.FailoverInstance(instance.name))
 
 
 @InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
 def TestRapiInstanceShutdown(instance):
   """Test stopping an instance via RAPI"""
 
 
 @InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
 def TestRapiInstanceShutdown(instance):
   """Test stopping an instance via RAPI"""
-  _WaitForRapiJob(_rapi_client.ShutdownInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.ShutdownInstance(instance.name))
 
 
 @InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
 def TestRapiInstanceStartup(instance):
   """Test starting an instance via RAPI"""
 
 
 @InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
 def TestRapiInstanceStartup(instance):
   """Test starting an instance via RAPI"""
-  _WaitForRapiJob(_rapi_client.StartupInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.StartupInstance(instance.name))
 
 
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
 
 
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
@@ -664,22 +672,26 @@ def TestRapiInstanceRenameAndBack(rename_source, rename_target):
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
 def TestRapiInstanceReinstall(instance):
   """Test reinstalling an instance via RAPI"""
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
 def TestRapiInstanceReinstall(instance):
   """Test reinstalling an instance via RAPI"""
-  _WaitForRapiJob(_rapi_client.ReinstallInstance(instance["name"]))
+  _WaitForRapiJob(_rapi_client.ReinstallInstance(instance.name))
   # By default, the instance is started again
   qa_utils.RunInstanceCheck(instance, True)
 
   # Reinstall again without starting
   # By default, the instance is started again
   qa_utils.RunInstanceCheck(instance, True)
 
   # Reinstall again without starting
-  _WaitForRapiJob(_rapi_client.ReinstallInstance(instance["name"],
+  _WaitForRapiJob(_rapi_client.ReinstallInstance(instance.name,
                                                  no_startup=True))
 
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceReplaceDisks(instance):
   """Test replacing instance disks via RAPI"""
                                                  no_startup=True))
 
 
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceReplaceDisks(instance):
   """Test replacing instance disks via RAPI"""
+  if not IsDiskReplacingSupported(instance):
+    print qa_utils.FormatInfo("Instance doesn't support disk replacing,"
+                              " skipping test")
+    return
   fn = _rapi_client.ReplaceInstanceDisks
   fn = _rapi_client.ReplaceInstanceDisks
-  _WaitForRapiJob(fn(instance["name"],
+  _WaitForRapiJob(fn(instance.name,
                      mode=constants.REPLACE_DISK_AUTO, disks=[]))
                      mode=constants.REPLACE_DISK_AUTO, disks=[]))
-  _WaitForRapiJob(fn(instance["name"],
+  _WaitForRapiJob(fn(instance.name,
                      mode=constants.REPLACE_DISK_SEC, disks="0"))
 
 
                      mode=constants.REPLACE_DISK_SEC, disks="0"))
 
 
@@ -689,7 +701,7 @@ def TestRapiInstanceModify(instance):
   default_hv = qa_config.GetDefaultHypervisor()
 
   def _ModifyInstance(**kwargs):
   default_hv = qa_config.GetDefaultHypervisor()
 
   def _ModifyInstance(**kwargs):
-    _WaitForRapiJob(_rapi_client.ModifyInstance(instance["name"], **kwargs))
+    _WaitForRapiJob(_rapi_client.ModifyInstance(instance.name, **kwargs))
 
   _ModifyInstance(beparams={
     constants.BE_VCPUS: 3,
 
   _ModifyInstance(beparams={
     constants.BE_VCPUS: 3,
@@ -718,17 +730,17 @@ def TestRapiInstanceModify(instance):
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceConsole(instance):
   """Test getting instance console information via RAPI"""
 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
 def TestRapiInstanceConsole(instance):
   """Test getting instance console information via RAPI"""
-  result = _rapi_client.GetInstanceConsole(instance["name"])
+  result = _rapi_client.GetInstanceConsole(instance.name)
   console = objects.InstanceConsole.FromDict(result)
   AssertEqual(console.Validate(), True)
   console = objects.InstanceConsole.FromDict(result)
   AssertEqual(console.Validate(), True)
-  AssertEqual(console.instance, qa_utils.ResolveInstanceName(instance["name"]))
+  AssertEqual(console.instance, qa_utils.ResolveInstanceName(instance.name))
 
 
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
 def TestRapiStoppedInstanceConsole(instance):
   """Test getting stopped instance's console information via RAPI"""
   try:
 
 
 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
 def TestRapiStoppedInstanceConsole(instance):
   """Test getting stopped instance's console information via RAPI"""
   try:
-    _rapi_client.GetInstanceConsole(instance["name"])
+    _rapi_client.GetInstanceConsole(instance.name)
   except rapi.client.GanetiApiError, err:
     AssertEqual(err.code, 503)
   else:
   except rapi.client.GanetiApiError, err:
     AssertEqual(err.code, 503)
   else:
@@ -744,7 +756,7 @@ def GetOperatingSystems():
 
 
 def TestInterClusterInstanceMove(src_instance, dest_instance,
 
 
 def TestInterClusterInstanceMove(src_instance, dest_instance,
-                                 pnode, snode, tnode):
+                                 inodes, tnode):
   """Test tools/move-instance"""
   master = qa_config.GetMasterNode()
 
   """Test tools/move-instance"""
   master = qa_config.GetMasterNode()
 
@@ -752,20 +764,26 @@ def TestInterClusterInstanceMove(src_instance, dest_instance,
   rapi_pw_file.write(_rapi_password)
   rapi_pw_file.flush()
 
   rapi_pw_file.write(_rapi_password)
   rapi_pw_file.flush()
 
+  dest_instance.SetDiskTemplate(src_instance.disk_template)
+
   # TODO: Run some instance tests before moving back
 
   # TODO: Run some instance tests before moving back
 
-  if snode is None:
+  if len(inodes) > 1:
+    # No disk template currently requires more than 1 secondary node. If this
+    # changes, either this test must be skipped or the script must be updated.
+    assert len(inodes) == 2
+    snode = inodes[1]
+  else:
     # instance is not redundant, but we still need to pass a node
     # (which will be ignored)
     # instance is not redundant, but we still need to pass a node
     # (which will be ignored)
-    fsec = tnode
-  else:
-    fsec = snode
+    snode = tnode
+  pnode = inodes[0]
   # note: pnode:snode are the *current* nodes, so we move it first to
   # tnode:pnode, then back to pnode:snode
   # note: pnode:snode are the *current* nodes, so we move it first to
   # tnode:pnode, then back to pnode:snode
-  for si, di, pn, sn in [(src_instance["name"], dest_instance["name"],
-                          tnode["primary"], pnode["primary"]),
-                         (dest_instance["name"], src_instance["name"],
-                          pnode["primary"], fsec["primary"])]:
+  for si, di, pn, sn in [(src_instance.name, dest_instance.name,
+                          tnode.primary, pnode.primary),
+                         (dest_instance.name, src_instance.name,
+                          pnode.primary, snode.primary)]:
     cmd = [
       "../tools/move-instance",
       "--verbose",
     cmd = [
       "../tools/move-instance",
       "--verbose",
@@ -776,8 +794,8 @@ def TestInterClusterInstanceMove(src_instance, dest_instance,
       "--dest-primary-node=%s" % pn,
       "--dest-secondary-node=%s" % sn,
       "--net=0:mac=%s" % constants.VALUE_GENERATE,
       "--dest-primary-node=%s" % pn,
       "--dest-secondary-node=%s" % sn,
       "--net=0:mac=%s" % constants.VALUE_GENERATE,
-      master["primary"],
-      master["primary"],
+      master.primary,
+      master.primary,
       si,
       ]
 
       si,
       ]