-
Iustin Pop authored
Currently, the logging in QA doesn't show the duration of the various steps, and if it is needed one has to perform log manipulation. This patch changes the output so that the log informatio is line based (as opposed to block-based), such that it's easy to grep for all log lines: ./qa/ganeti-qa.py --yes-do-it qa.json 2>&1|grep ^---- ---- 2010-10-08 14:40:21.730382 start Test SSH connection -------------- ---- 2010-10-08 14:40:23.156633 time=0:00:01.426251 Test SSH connection ---- 2010-10-08 14:40:23.156735 start ICMP ping each node -------------- ---- 2010-10-08 14:40:24.230479 time=0:00:01.073744 ICMP ping each node ---- 2010-10-08 14:40:24.230583 start Test availibility of Ganeti commands ---- 2010-10-08 14:40:32.314586 time=0:00:08.084003 Test availibility of Ganeti commands ---- 2010-10-08 14:40:32.314734 start gnt-node info -------------------- ---- 2010-10-08 14:40:32.860884 time=0:00:00.546150 gnt-node info ------ or just for the duration of the steps: ./qa/ganeti-qa.py --yes-do-it ../qa-mpgntac5.fra.json 2>&1|grep ^----.*time= ---- 2010-10-08 14:42:12.630067 time=0:00:01.239256 Test SSH connection ---- 2010-10-08 14:42:14.204393 time=0:00:01.574221 ICMP ping each node ---- 2010-10-08 14:42:22.170828 time=0:00:07.966331 Test availibility of Ganeti commands ---- 2010-10-08 14:42:22.701030 time=0:00:00.530037 gnt-node info ------ This will help with identifying slow steps or even graphing the QA duration. Signed-off-by:
Iustin Pop <iustin@google.com> Reviewed-by:
Michael Hanselmann <hansmi@google.com>
f89d59b9
ganeti-qa.py 12.42 KiB
#!/usr/bin/python -u
#
# Copyright (C) 2007, 2008, 2009, 2010 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Script for doing QA on Ganeti.
"""
import sys
import datetime
import optparse
import qa_cluster
import qa_config
import qa_daemon
import qa_env
import qa_instance
import qa_node
import qa_os
import qa_rapi
import qa_tags
import qa_utils
from ganeti import utils
from ganeti import rapi
import ganeti.rapi.client
def _FormatHeader(line, end=72, char="-"):
"""Fill a line up to the end column.
"""
line = "---- " + line + " "
line += "-" * (end-len(line))
line = line.rstrip()
return line
def RunTest(fn, *args):
"""Runs a test after printing a header.
"""
if fn.__doc__:
desc = fn.__doc__.splitlines()[0].strip()
else:
desc = "%r" % fn
desc = desc.rstrip(".")
tstart = datetime.datetime.now()
print
print _FormatHeader("%s start %s" % (tstart, desc))
try:
retval = fn(*args)
return retval
finally:
tstop = datetime.datetime.now()
tdelta = tstop - tstart
print _FormatHeader("%s time=%s %s" % (tstop, tdelta, desc))
def RunEnvTests():
"""Run several environment tests.
"""
if not qa_config.TestEnabled('env'):
return
RunTest(qa_env.TestSshConnection)
RunTest(qa_env.TestIcmpPing)
RunTest(qa_env.TestGanetiCommands)
def SetupCluster(rapi_user, rapi_secret):
"""Initializes the cluster.
@param rapi_user: Login user for RAPI
@param rapi_secret: Login secret for RAPI
"""
if qa_config.TestEnabled('create-cluster'):
RunTest(qa_cluster.TestClusterInit, rapi_user, rapi_secret)
RunTest(qa_node.TestNodeAddAll)
RunTest(qa_cluster.TestJobqueue)
else:
# consider the nodes are already there
qa_node.MarkNodeAddedAll()
if qa_config.TestEnabled('node-info'):
RunTest(qa_node.TestNodeInfo)
def RunClusterTests():
"""Runs tests related to gnt-cluster.
"""
if qa_config.TestEnabled("cluster-renew-crypto"):
RunTest(qa_cluster.TestClusterRenewCrypto)
if qa_config.TestEnabled('cluster-verify'):
RunTest(qa_cluster.TestClusterVerify)
if qa_config.TestEnabled('cluster-reserved-lvs'):
RunTest(qa_cluster.TestClusterReservedLvs)
if qa_config.TestEnabled('cluster-rename'):
RunTest(qa_cluster.TestClusterRename)
if qa_config.TestEnabled('cluster-info'):
RunTest(qa_cluster.TestClusterVersion)
RunTest(qa_cluster.TestClusterInfo)
RunTest(qa_cluster.TestClusterGetmaster)
if qa_config.TestEnabled('cluster-copyfile'):
RunTest(qa_cluster.TestClusterCopyfile)
if qa_config.TestEnabled('cluster-command'):
RunTest(qa_cluster.TestClusterCommand)
if qa_config.TestEnabled('cluster-burnin'):
RunTest(qa_cluster.TestClusterBurnin)
if qa_config.TestEnabled('cluster-master-failover'):
RunTest(qa_cluster.TestClusterMasterFailover)
if qa_rapi.Enabled():
RunTest(qa_rapi.TestVersion)
RunTest(qa_rapi.TestEmptyCluster)
def RunOsTests():
"""Runs all tests related to gnt-os.
"""
if not qa_config.TestEnabled('os'):
return
RunTest(qa_os.TestOsList)
RunTest(qa_os.TestOsDiagnose)
RunTest(qa_os.TestOsValid)
RunTest(qa_os.TestOsInvalid)
RunTest(qa_os.TestOsPartiallyValid)
RunTest(qa_os.TestOsModifyValid)
RunTest(qa_os.TestOsModifyInvalid)
RunTest(qa_os.TestOsStates)
def RunCommonInstanceTests(instance):
"""Runs a few tests that are common to all disk types.
"""
if qa_config.TestEnabled('instance-shutdown'):
RunTest(qa_instance.TestInstanceShutdown, instance)
RunTest(qa_instance.TestInstanceStartup, instance)
if qa_config.TestEnabled('instance-list'):
RunTest(qa_instance.TestInstanceList)
if qa_config.TestEnabled('instance-info'):
RunTest(qa_instance.TestInstanceInfo, instance)
if qa_config.TestEnabled('instance-modify'):
RunTest(qa_instance.TestInstanceModify, instance)
if qa_rapi.Enabled():
RunTest(qa_rapi.TestRapiInstanceModify, instance)
if qa_config.TestEnabled('instance-console'):
RunTest(qa_instance.TestInstanceConsole, instance)
if qa_config.TestEnabled('instance-reinstall'):
RunTest(qa_instance.TestInstanceShutdown, instance)
RunTest(qa_instance.TestInstanceReinstall, instance)
RunTest(qa_instance.TestInstanceStartup, instance)
if qa_config.TestEnabled('instance-reboot'):
RunTest(qa_instance.TestInstanceReboot, instance)
if qa_config.TestEnabled('instance-rename'):
rename_target = qa_config.get("rename", None)
if rename_target is None:
print qa_utils.FormatError("Can rename instance, 'rename' entry is"
" missing from configuration")
else:
RunTest(qa_instance.TestInstanceShutdown, instance)
RunTest(qa_instance.TestInstanceRename, instance, rename_target)
if qa_rapi.Enabled():
RunTest(qa_rapi.TestRapiInstanceRename, instance, rename_target)
RunTest(qa_instance.TestInstanceStartup, instance)
if qa_config.TestEnabled('tags'):
RunTest(qa_tags.TestInstanceTags, instance)
if qa_config.TestEnabled('node-volumes'):
RunTest(qa_node.TestNodeVolumes)
if qa_config.TestEnabled("node-storage"):
RunTest(qa_node.TestNodeStorage)
if qa_rapi.Enabled():
RunTest(qa_rapi.TestInstance, instance)
def RunExportImportTests(instance, pnode, snode):
"""Tries to export and import the instance.
@param pnode: current primary node of the instance
@param snode: current secondary node of the instance, if any,
otherwise None
"""
if qa_config.TestEnabled('instance-export'):
RunTest(qa_instance.TestInstanceExportNoTarget, instance)
expnode = qa_config.AcquireNode(exclude=pnode)
try:
name = RunTest(qa_instance.TestInstanceExport, instance, expnode)
RunTest(qa_instance.TestBackupList, expnode)
if qa_config.TestEnabled('instance-import'):
newinst = qa_config.AcquireInstance()
try:
RunTest(qa_instance.TestInstanceImport, pnode, newinst,
expnode, name)
RunTest(qa_instance.TestInstanceRemove, newinst)
finally:
qa_config.ReleaseInstance(newinst)
finally:
qa_config.ReleaseNode(expnode)
if (qa_rapi.Enabled() and
qa_config.TestEnabled("inter-cluster-instance-move")):
newinst = qa_config.AcquireInstance()
try:
if snode is None:
excl = [pnode]
else:
excl = [pnode, snode]
tnode = qa_config.AcquireNode(exclude=excl)
try:
RunTest(qa_rapi.TestInterClusterInstanceMove, instance, newinst,
pnode, snode, tnode)
finally:
qa_config.ReleaseNode(tnode)
finally:
qa_config.ReleaseInstance(newinst)
def RunDaemonTests(instance, pnode):
"""Test the ganeti-watcher script.
"""
automatic_restart = \
qa_config.TestEnabled('instance-automatic-restart')
consecutive_failures = \
qa_config.TestEnabled('instance-consecutive-failures')
if automatic_restart or consecutive_failures:
qa_daemon.PrintCronWarning()
if automatic_restart:
RunTest(qa_daemon.TestInstanceAutomaticRestart, pnode, instance)
if consecutive_failures:
RunTest(qa_daemon.TestInstanceConsecutiveFailures, pnode, instance)
def RunHardwareFailureTests(instance, pnode, snode):
"""Test cluster internal hardware failure recovery.
"""
if qa_config.TestEnabled('instance-failover'):
RunTest(qa_instance.TestInstanceFailover, instance)
if qa_config.TestEnabled("instance-migrate"):
RunTest(qa_instance.TestInstanceMigrate, instance)
if qa_rapi.Enabled():
RunTest(qa_rapi.TestRapiInstanceMigrate, instance)
if qa_config.TestEnabled('instance-replace-disks'):
othernode = qa_config.AcquireNode(exclude=[pnode, snode])
try:
RunTest(qa_instance.TestReplaceDisks,
instance, pnode, snode, othernode)
finally:
qa_config.ReleaseNode(othernode)
if qa_config.TestEnabled('node-evacuate'):
RunTest(qa_node.TestNodeEvacuate, pnode, snode)
if qa_config.TestEnabled('node-failover'):
RunTest(qa_node.TestNodeFailover, pnode, snode)
if qa_config.TestEnabled('instance-disk-failure'):
RunTest(qa_instance.TestInstanceMasterDiskFailure,
instance, pnode, snode)
RunTest(qa_instance.TestInstanceSecondaryDiskFailure,
instance, pnode, snode)
@rapi.client.UsesRapiClient
def main():
"""Main program.
"""
parser = optparse.OptionParser(usage="%prog [options] <config-file>")
parser.add_option('--yes-do-it', dest='yes_do_it',
action="store_true",
help="Really execute the tests")
(qa_config.options, args) = parser.parse_args()
if len(args) == 1:
(config_file, ) = args
else:
parser.error("Wrong number of arguments.")
if not qa_config.options.yes_do_it:
print ("Executing this script irreversibly destroys any Ganeti\n"
"configuration on all nodes involved. If you really want\n"
"to start testing, supply the --yes-do-it option.")
sys.exit(1)
qa_config.Load(config_file)
rapi_user = "ganeti-qa"
rapi_secret = utils.GenerateSecret()
RunEnvTests()
SetupCluster(rapi_user, rapi_secret)
# Load RAPI certificate
qa_rapi.Setup(rapi_user, rapi_secret)
RunClusterTests()
RunOsTests()
if qa_config.TestEnabled('tags'):
RunTest(qa_tags.TestClusterTags)
if qa_config.TestEnabled('node-readd'):
master = qa_config.GetMasterNode()
pnode = qa_config.AcquireNode(exclude=master)
try:
RunTest(qa_node.TestNodeReadd, pnode)
finally:
qa_config.ReleaseNode(pnode)
pnode = qa_config.AcquireNode()
try:
if qa_config.TestEnabled('tags'):
RunTest(qa_tags.TestNodeTags, pnode)
if qa_rapi.Enabled():
RunTest(qa_rapi.TestNode, pnode)
if qa_config.TestEnabled("instance-add-plain-disk"):
for use_client in [True, False]:
rapi_instance = RunTest(qa_rapi.TestRapiInstanceAdd, pnode,
use_client)
RunCommonInstanceTests(rapi_instance)
RunTest(qa_rapi.TestRapiInstanceRemove, rapi_instance, use_client)
del rapi_instance
if qa_config.TestEnabled('instance-add-plain-disk'):
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
RunCommonInstanceTests(instance)
RunExportImportTests(instance, pnode, None)
RunDaemonTests(instance, pnode)
RunTest(qa_instance.TestInstanceRemove, instance)
del instance
multinode_tests = [
('instance-add-drbd-disk',
qa_instance.TestInstanceAddWithDrbdDisk),
]
for name, func in multinode_tests:
if qa_config.TestEnabled(name):
snode = qa_config.AcquireNode(exclude=pnode)
try:
instance = RunTest(func, pnode, snode)
RunCommonInstanceTests(instance)
if qa_config.TestEnabled('instance-convert-disk'):
RunTest(qa_instance.TestInstanceShutdown, instance)
RunTest(qa_instance.TestInstanceConvertDisk, instance, snode)
RunTest(qa_instance.TestInstanceStartup, instance)
RunExportImportTests(instance, pnode, snode)
RunHardwareFailureTests(instance, pnode, snode)
RunTest(qa_instance.TestInstanceRemove, instance)
del instance
finally:
qa_config.ReleaseNode(snode)
if (qa_config.TestEnabled('instance-add-plain-disk') and
qa_config.TestEnabled("instance-export")):
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
expnode = qa_config.AcquireNode(exclude=pnode)
try:
RunTest(qa_instance.TestInstanceExportWithRemove, instance, expnode)
RunTest(qa_instance.TestBackupList, expnode)
finally:
qa_config.ReleaseNode(expnode)
del expnode
del instance
finally:
qa_config.ReleaseNode(pnode)
if qa_config.TestEnabled('create-cluster'):
RunTest(qa_node.TestNodeRemoveAll)
if qa_config.TestEnabled('cluster-destroy'):
RunTest(qa_cluster.TestClusterDestroy)
if __name__ == '__main__':
main()