This script can be used to check if an instance is running or stopped at
various points during a QA run. Environment variables are used to pass
the most essential information.
---
qa/ganeti-qa.py | 36 ++++++++++++++++++++++++++++++++----
qa/qa-sample.json | 3 +++
qa/qa_config.py | 19 +++++++++++++++++++
qa/qa_utils.py | 35 +++++++++++++++++++++++++++++++++++
4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py
index d35ebd6..01a2b1e 100755
--- a/qa/ganeti-qa.py
+++ b/qa/ganeti-qa.py
@@ -72,7 +72,7 @@ def _DescriptionOf(fn):
return desc.rstrip(".")
-def RunTest(fn, *args):
+def RunTest(fn, *args, **kwargs):
"""Runs a test after printing a header.
"""
@@ -85,7 +85,7 @@ def RunTest(fn, *args):
print _FormatHeader("%s start %s" % (tstart, desc))
try:
- retval = fn(*args)
+ retval = fn(*args, **kwargs)
return retval
finally:
tstop = datetime.datetime.now()
@@ -93,7 +93,7 @@ def RunTest(fn, *args):
print _FormatHeader("%s time=%s %s" % (tstop, tdelta, desc))
-def RunTestIf(testnames, fn, *args):
+def RunTestIf(testnames, fn, *args, **kwargs):
"""Runs a test conditionally.
@param testnames: either a single test name in the configuration
@@ -101,7 +101,7 @@ def RunTestIf(testnames, fn, *args):
"""
if qa_config.TestEnabled(testnames):
- RunTest(fn, *args)
+ RunTest(fn, *args, **kwargs)
else:
tstart = datetime.datetime.now()
desc = _DescriptionOf(fn)
@@ -227,18 +227,29 @@ def RunCommonInstanceTests(instance):
"""Runs a few tests that are common to all disk types.
"""
+ RunTest(qa_utils.CheckInstance, instance)
RunTestIf("instance-shutdown", qa_instance.TestInstanceShutdown, instance)
+ RunTestIf("instance-shutdown", qa_utils.CheckInstance,
+ instance, running=False)
RunTestIf(["instance-shutdown", "instance-console", "rapi"],
qa_rapi.TestRapiStoppedInstanceConsole, instance)
RunTestIf(["instance-shutdown", "instance-modify"],
qa_instance.TestInstanceStoppedModify, instance)
+ if (qa_config.TestEnabled(["instance-console", "rapi"]) or
+ qa_config.TestEnabled("instance-modify")):
+ RunTestIf(["instance-shutdown"], qa_utils.CheckInstance,
+ instance, running=False)
RunTestIf("instance-shutdown", qa_instance.TestInstanceStartup, instance)
+ RunTestIf("instance-shutdown", qa_utils.CheckInstance, instance)
# Test shutdown/start via RAPI
RunTestIf(["instance-shutdown", "rapi"],
qa_rapi.TestRapiInstanceShutdown, instance)
+ RunTestIf(["instance-shutdown", "rapi"], qa_utils.CheckInstance,
+ instance, running=False)
RunTestIf(["instance-shutdown", "rapi"],
qa_rapi.TestRapiInstanceStartup, instance)
+ RunTestIf(["instance-shutdown", "rapi"], qa_utils.CheckInstance, instance)
RunTestIf("instance-list", qa_instance.TestInstanceList)
@@ -247,6 +258,7 @@ def RunCommonInstanceTests(instance):
RunTestIf("instance-modify", qa_instance.TestInstanceModify, instance)
RunTestIf(["instance-modify", "rapi"],
qa_rapi.TestRapiInstanceModify, instance)
+ RunTestIf("instance-modify", qa_utils.CheckInstance, instance)
RunTestIf("instance-console", qa_instance.TestInstanceConsole, instance)
RunTestIf(["instance-console", "rapi"],
@@ -256,6 +268,7 @@ def RunCommonInstanceTests(instance):
qa_config.TestEnabled("instance-rename")):
# shutdown instance for any 'down' tests
RunTest(qa_instance.TestInstanceShutdown, instance)
+ RunTest(qa_utils.CheckInstance, instance, running=False)
# now run the 'down' state tests
RunTestIf("instance-reinstall", qa_instance.TestInstanceReinstall,
instance)
@@ -263,6 +276,7 @@ def RunCommonInstanceTests(instance):
qa_rapi.TestRapiInstanceReinstall, instance)
# RAPI reinstall will leave the instance up by default, so we have
# to stop it again
+ RunTestIf(["instance-reinstall", "rapi"], qa_utils.CheckInstance, instance)
RunTestIf(["instance-reinstall", "rapi"],
qa_rapi.TestRapiInstanceShutdown, instance)
@@ -281,10 +295,13 @@ def RunCommonInstanceTests(instance):
RunTestIf("rapi", qa_rapi.TestRapiInstanceRenameAndBack,
rename_source, rename_target)
+ RunTest(qa_utils.CheckInstance, instance, running=False)
+
# Start the instance again
RunTest(qa_instance.TestInstanceStartup, instance)
RunTestIf("instance-reboot", qa_instance.TestInstanceReboot, instance)
+ RunTestIf("instance-reboot", qa_utils.CheckInstance, instance)
RunTestIf("tags", qa_tags.TestInstanceTags, instance)
@@ -298,6 +315,8 @@ def RunCommonInstanceTests(instance):
# Some jobs have been run, let's test listing them
RunTestIf("job-list", qa_job.TestJobList)
+ RunTestIf("instance-reboot", qa_utils.CheckInstance, instance)
+
def RunCommonNodeTests():
"""Run a few common node tests.
@@ -350,7 +369,9 @@ def RunExportImportTests(instance, pnode, snode):
try:
RunTest(qa_instance.TestInstanceImport, pnode, newinst,
expnode, name)
+ RunTest(qa_utils.CheckInstance, newinst)
RunTest(qa_instance.TestInstanceRemove, newinst)
+ RunTest(qa_utils.CheckInstance, newinst, running=False)
finally:
qa_config.ReleaseInstance(newinst)
finally:
@@ -462,6 +483,7 @@ def RunQa():
use_client)
RunCommonInstanceTests(rapi_instance)
RunTest(qa_rapi.TestRapiInstanceRemove, rapi_instance, use_client)
+ RunTest(qa_utils.CheckInstance, rapi_instance, running=False)
del rapi_instance
if qa_config.TestEnabled("instance-add-plain-disk"):
@@ -473,6 +495,7 @@ def RunQa():
RunDaemonTests(instance)
RunRepairDiskSizes()
RunTest(qa_instance.TestInstanceRemove, instance)
+ RunTest(qa_utils.CheckInstance, instance, running=False)
del instance
multinode_tests = [
@@ -493,11 +516,14 @@ def RunQa():
if qa_config.TestEnabled("instance-convert-disk"):
RunTest(qa_instance.TestInstanceShutdown, instance)
RunTest(qa_instance.TestInstanceConvertDisk, instance, snode)
+ RunTest(qa_utils.CheckInstance, instance, running=False)
RunTest(qa_instance.TestInstanceStartup, instance)
+ RunTest(qa_utils.CheckInstance, instance)
RunExportImportTests(instance, pnode, snode)
RunHardwareFailureTests(instance, pnode, snode)
RunRepairDiskSizes()
RunTest(qa_instance.TestInstanceRemove, instance)
+ RunTest(qa_utils.CheckInstance, instance, running=False)
del instance
finally:
qa_config.ReleaseNode(snode)
@@ -507,9 +533,11 @@ def RunQa():
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
expnode = qa_config.AcquireNode(exclude=pnode)
try:
+ RunTest(qa_utils.CheckInstance, instance)
if shutdown:
# Stop instance before exporting and removing it
RunTest(qa_instance.TestInstanceShutdown, instance)
+ RunTest(qa_utils.CheckInstance, instance, running=False)
RunTest(qa_instance.TestInstanceExportWithRemove, instance, expnode)
RunTest(qa_instance.TestBackupList, expnode)
finally:
diff --git a/qa/qa-sample.json b/qa/qa-sample.json
index 0cfdf2e..a8f98ff 100644
--- a/qa/qa-sample.json
+++ b/qa/qa-sample.json
@@ -24,6 +24,9 @@
"disk": ["1G", "512M"],
"disk-growth": ["2G", "768M"],
+ "# Script to check instance status": null,
+ "instance-check": null,
+
"nodes": [
{
"# Master node": null,
diff --git a/qa/qa_config.py b/qa/qa_config.py
index e058a71..ccd141f 100644
--- a/qa/qa_config.py
+++ b/qa/qa_config.py
@@ -23,6 +23,7 @@
"""
+import os
from ganeti import utils
from ganeti import serializer
@@ -31,6 +32,9 @@ from ganeti import compat
import qa_error
+_INSTANCE_CHECK_KEY = "instance-check"
+
+
cfg = None
options = None
@@ -55,6 +59,14 @@ def Validate():
raise qa_error.Error("Config options 'disk' and 'disk-growth' must have"
" the same number of items")
+ check = GetInstanceCheckScript()
+ if check:
+ try:
+ os.stat(check)
+ except EnvironmentError, err:
+ raise qa_error.Error("Can't find instance check script '%s': %s" %
+ (check, err))
+
def get(name, default=None):
return cfg.get(name, default)
@@ -78,6 +90,13 @@ def TestEnabled(tests):
return compat.all(all_tests.get(name, default) for name in tests)
+def GetInstanceCheckScript():
+ """Returns path to instance check script or C{None}.
+
+ """
+ return cfg.get(_INSTANCE_CHECK_KEY, None)
+
+
def GetMasterNode():
return cfg["nodes"][0]
diff --git a/qa/qa_utils.py b/qa/qa_utils.py
index f0ef63c..63c708b 100644
--- a/qa/qa_utils.py
+++ b/qa/qa_utils.py
@@ -45,6 +45,9 @@ _RESET_SEQ = None
_MULTIPLEXERS = {}
+#: Unique ID per QA run
+_RUN_UUID = utils.NewUUID()
+
def _SetupColours():
"""Initializes the colour constants.
@@ -374,6 +377,38 @@ def GetNodeInstances(node, secondaries=False):
return instances
+def CheckInstance(instance, running=True):
+ """Instance check.
+
+ """
+ script = qa_config.GetInstanceCheckScript()
+ if not script:
+ return
+
+ master_node = qa_config.GetMasterNode()
+
+ # Build command to connect to master node
+ master_ssh = GetSSHCommand(master_node["primary"], "--")
+
+ if running:
+ running_shellval = "1"
+ else:
+ running_shellval = ""
+
+ args = [script, instance["name"]]
+ env = {
+ "PATH": constants.HOOKS_PATH,
+ "RUN_UUID": _RUN_UUID,
+ "MASTER_SSH": utils.ShellQuoteArgs(master_ssh),
+ "INSTANCE_NAME": instance["name"],
+ "INSTANCE_RUNNING": running_shellval,
+ }
+
+ result = os.spawnve(os.P_WAIT, script, args, env)
+ if result != 0:
+ raise qa_error.Error("Instance check failed with result %s" % result)
+
+
def _SelectQueryFields(rnd, fields):
"""Generates a list of fields for query tests.
--
1.7.6