Commit c9e05005 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

QA: Infrastructure for hook script to check instance status



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.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 741c6d91
......@@ -23,6 +23,7 @@ Version 2.6.0 beta1
- Deprecation warnings due to pycrypto/paramiko import in
tools/setup-ssh have been silenced, as usually they are safe; please
make sure to run an up-to-date paramiko version
- The QA scripts now depend on Python 2.5 or above
Version 2.5.0
......
......@@ -24,6 +24,9 @@
"disk": ["1G", "512M"],
"disk-growth": ["2G", "768M"],
"# Script to check instance status": null,
"instance-check": null,
"nodes": [
{
"# Master node": null,
......
......@@ -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)
......@@ -135,6 +147,13 @@ def TestEnabled(tests, _cfg=None):
tests, compat.all)
def GetInstanceCheckScript():
"""Returns path to instance check script or C{None}.
"""
return cfg.get(_INSTANCE_CHECK_KEY, None)
def GetMasterNode():
return cfg["nodes"][0]
......
......@@ -30,9 +30,15 @@ import subprocess
import random
import tempfile
try:
import functools
except ImportError, err:
raise ImportError("Python 2.5 or higher is required: %s" % err)
from ganeti import utils
from ganeti import compat
from ganeti import constants
from ganeti import ht
import qa_config
import qa_error
......@@ -45,6 +51,16 @@ _RESET_SEQ = None
_MULTIPLEXERS = {}
#: Unique ID per QA run
_RUN_UUID = utils.NewUUID()
(INST_DOWN,
INST_UP) = range(500, 502)
(FIRST_ARG,
RETURN_VALUE) = range(1000, 1002)
def _SetupColours():
"""Initializes the colour constants.
......@@ -522,3 +538,91 @@ def RemoveFromEtcHosts(hostnames):
quoted_tmp_hosts))
except qa_error.Error:
AssertCommand(["rm", tmp_hosts])
def RunInstanceCheck(instance, running):
"""Check if instance is running or not.
"""
script = qa_config.GetInstanceCheckScript()
if not script:
return
master_node = qa_config.GetMasterNode()
instance_name = instance["name"]
# Build command to connect to master node
master_ssh = GetSSHCommand(master_node["primary"], "--")
if running:
running_shellval = "1"
running_text = ""
else:
running_shellval = ""
running_text = "not "
print FormatInfo("Checking if instance '%s' is %srunning" %
(instance_name, running_text))
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)
_TInstCheck = ht.TStrictDict(False, False, {
"name": ht.TNonEmptyString,
})
def _InstanceCheckInner(expected, instarg, args, result):
"""Helper function used by L{InstanceCheck}.
"""
if instarg == FIRST_ARG:
instance = args[0]
elif instarg == RETURN_VALUE:
instance = result
else:
raise Exception("Invalid value '%s' for instance argument" % instarg)
if expected in (INST_DOWN, INST_UP):
if not _TInstCheck(instance):
raise Exception("Invalid instance: %s" % instance)
RunInstanceCheck(instance, (expected == INST_UP))
elif expected is not None:
raise Exception("Invalid value '%s'" % expected)
def InstanceCheck(before, after, instarg):
"""Decorator to check instance status before and after test.
@param before: L{INST_DOWN} if instance must be stopped before test,
L{INST_UP} if instance must be running before test, L{None} to not check.
@param after: L{INST_DOWN} if instance must be stopped after test,
L{INST_UP} if instance must be running after test, L{None} to not check.
@param instarg: L{FIRST_ARG} to use first argument to test as instance (a
dictionary), L{RETURN_VALUE} to use return value (disallows pre-checks)
"""
def decorator(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
_InstanceCheckInner(before, instarg, args, NotImplemented)
result = fn(*args, **kwargs)
_InstanceCheckInner(after, instarg, args, result)
return result
return wrapper
return decorator
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment