#
#
-# 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
import tempfile
import random
+import re
+import itertools
from ganeti import utils
from ganeti import constants
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 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
_rapi_ca = None
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()
"mtotal", "mnode", "mfree",
"pinst_cnt", "sinst_cnt", "tags")
-GROUP_FIELDS = frozenset([
+GROUP_FIELDS = compat.UniqueFrozenset([
"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",
def _VerifyReturnsJob(data):
- AssertMatch(data, r"^\d+$")
+ if not isinstance(data, int):
+ AssertMatch(data, r"^\d+$")
def TestVersion():
for what in constants.QR_VIA_RAPI:
if what == constants.QR_JOB:
namefield = "id"
+ elif what == constants.QR_EXPORT:
+ namefield = "export"
else:
namefield = "name"
if what == constants.QR_NODE:
# Test with filter
- (nodes, ) = _DoTests([("/2/query/%s" % what,
- compat.partial(_Check, ["name", "master"]), "PUT", {
- "fields": ["name", "master"],
- "filter": [qlang.OP_TRUE, "master"],
- })])
+ (nodes, ) = _DoTests(
+ [("/2/query/%s" % what,
+ compat.partial(_Check, ["name", "master"]), "PUT",
+ {"fields": ["name", "master"],
+ "filter": [qlang.OP_TRUE, "master"],
+ })])
qresult = objects.QueryResponse.FromDict(nodes)
AssertEqual(qresult.data, [
[[constants.RS_NORMAL, master_name], [constants.RS_NORMAL, True]],
])
+@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
def TestInstance(instance):
"""Testing getting instance(s) info via remote API.
])
+def _FilterTags(seq):
+ """Removes unwanted tags from a sequence.
+
+ """
+ ignore_re = qa_config.get("ignore-tags-re", None)
+
+ if ignore_re:
+ return itertools.ifilterfalse(re.compile(ignore_re).match, seq)
+ else:
+ return seq
+
+
def TestTags(kind, name, tags):
"""Tests .../tags resources.
raise errors.ProgrammerError("Unknown tag kind")
def _VerifyTags(data):
- AssertEqual(sorted(tags), sorted(data))
+ AssertEqual(sorted(tags), sorted(_FilterTags(data)))
queryargs = "&".join("tag=%s" % i for i in tags)
"""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 = {
def TestRapiInstanceAdd(node, use_client):
"""Test adding a new instance via RAPI"""
instance = qa_config.AcquireInstance()
+ qa_config.SetInstanceTemplate(instance, constants.DT_PLAIN)
try:
disk_sizes = [utils.ParseUnit(size) for size in qa_config.get("disk")]
disks = [{"size": size} for size in disk_sizes]
- nics = [{}]
+ nic0_mac = qa_config.GetInstanceNicMac(instance,
+ default=constants.VALUE_GENERATE)
+ nics = [{
+ constants.INIC_MAC: nic0_mac,
+ }]
beparams = {
constants.BE_MAXMEM: utils.ParseUnit(qa_config.get(constants.BE_MAXMEM)),
raise
+@InstanceCheck(None, INST_DOWN, FIRST_ARG)
def TestRapiInstanceRemove(instance, use_client):
"""Test removing instance via RAPI"""
if use_client:
qa_config.ReleaseInstance(instance)
+@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
_WaitForRapiJob(_rapi_client.MigrateInstance(instance["name"]))
+ qa_utils.RunInstanceCheck(instance, True)
# And back to previous primary
_WaitForRapiJob(_rapi_client.MigrateInstance(instance["name"]))
+@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
_WaitForRapiJob(_rapi_client.FailoverInstance(instance["name"]))
+ qa_utils.RunInstanceCheck(instance, True)
# And back to previous primary
_WaitForRapiJob(_rapi_client.FailoverInstance(instance["name"]))
+@InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
def TestRapiInstanceShutdown(instance):
"""Test stopping an instance via RAPI"""
_WaitForRapiJob(_rapi_client.ShutdownInstance(instance["name"]))
+@InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
def TestRapiInstanceStartup(instance):
"""Test starting an instance via RAPI"""
_WaitForRapiJob(_rapi_client.StartupInstance(instance["name"]))
+@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
def TestRapiInstanceRenameAndBack(rename_source, rename_target):
"""Test renaming instance via RAPI
"""
_WaitForRapiJob(_rapi_client.RenameInstance(rename_source, rename_target))
+ qa_utils.RunInstanceCheck(rename_source, False)
+ qa_utils.RunInstanceCheck(rename_target, False)
_WaitForRapiJob(_rapi_client.RenameInstance(rename_target, rename_source))
+ qa_utils.RunInstanceCheck(rename_target, False)
+@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
def TestRapiInstanceReinstall(instance):
"""Test reinstalling an instance via RAPI"""
_WaitForRapiJob(_rapi_client.ReinstallInstance(instance["name"]))
+ # By default, the instance is started again
+ qa_utils.RunInstanceCheck(instance, True)
+
+ # Reinstall again without starting
+ _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"""
- _WaitForRapiJob(_rapi_client.ReplaceInstanceDisks(instance["name"],
- mode=constants.REPLACE_DISK_AUTO, disks=[]))
- _WaitForRapiJob(_rapi_client.ReplaceInstanceDisks(instance["name"],
- mode=constants.REPLACE_DISK_SEC, disks="0"))
-
-
+ if not IsDiskReplacingSupported(instance):
+ print qa_utils.FormatInfo("Instance doesn't support disk replacing,"
+ " skipping test")
+ return
+ fn = _rapi_client.ReplaceInstanceDisks
+ _WaitForRapiJob(fn(instance["name"],
+ mode=constants.REPLACE_DISK_AUTO, disks=[]))
+ _WaitForRapiJob(fn(instance["name"],
+ mode=constants.REPLACE_DISK_SEC, disks="0"))
+
+
+@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
def TestRapiInstanceModify(instance):
"""Test modifying instance via RAPI"""
+ default_hv = qa_config.GetDefaultHypervisor()
+
def _ModifyInstance(**kwargs):
_WaitForRapiJob(_rapi_client.ModifyInstance(instance["name"], **kwargs))
- _ModifyInstance(hvparams={
- constants.HV_KERNEL_ARGS: "single",
- })
-
_ModifyInstance(beparams={
constants.BE_VCPUS: 3,
})
constants.BE_VCPUS: constants.VALUE_DEFAULT,
})
- _ModifyInstance(hvparams={
- constants.HV_KERNEL_ARGS: constants.VALUE_DEFAULT,
- })
-
-
+ if default_hv == constants.HT_XEN_PVM:
+ _ModifyInstance(hvparams={
+ constants.HV_KERNEL_ARGS: "single",
+ })
+ _ModifyInstance(hvparams={
+ constants.HV_KERNEL_ARGS: constants.VALUE_DEFAULT,
+ })
+ elif default_hv == constants.HT_XEN_HVM:
+ _ModifyInstance(hvparams={
+ constants.HV_BOOT_ORDER: "acn",
+ })
+ _ModifyInstance(hvparams={
+ constants.HV_BOOT_ORDER: constants.VALUE_DEFAULT,
+ })
+
+
+@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
def TestRapiInstanceConsole(instance):
"""Test getting instance console information via RAPI"""
result = _rapi_client.GetInstanceConsole(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:
def TestInterClusterInstanceMove(src_instance, dest_instance,
- pnode, snode, tnode):
+ inodes, tnode):
"""Test tools/move-instance"""
master = qa_config.GetMasterNode()
rapi_pw_file.write(_rapi_password)
rapi_pw_file.flush()
+ qa_config.SetInstanceTemplate(dest_instance,
+ qa_config.GetInstanceTemplate(src_instance))
+
# 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)
- 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
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"])]:
+ pnode["primary"], snode["primary"])]:
cmd = [
"../tools/move-instance",
"--verbose",
si,
]
+ qa_utils.RunInstanceCheck(di, False)
AssertEqual(StartLocalCommand(cmd).wait(), 0)
+ qa_utils.RunInstanceCheck(si, False)
+ qa_utils.RunInstanceCheck(di, True)