X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/e5c2accd7ea5c87fdba3d1a3d753bf668db96498..8e66b9bfff134a6190aebdbe786a102778b3ecec:/qa/ganeti-qa.py diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py index 1c2f746..de9c194 100755 --- a/qa/ganeti-qa.py +++ b/qa/ganeti-qa.py @@ -1,7 +1,7 @@ #!/usr/bin/python -u # -# Copyright (C) 2007, 2008, 2009, 2010 Google Inc. +# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 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 @@ -23,6 +23,9 @@ """ +# pylint: disable=C0103 +# due to invalid name + import sys import datetime import optparse @@ -35,14 +38,17 @@ import qa_group import qa_instance import qa_node import qa_os +import qa_job import qa_rapi import qa_tags import qa_utils from ganeti import utils -from ganeti import rapi +from ganeti import rapi # pylint: disable=W0611 +from ganeti import constants -import ganeti.rapi.client +import ganeti.rapi.client # pylint: disable=W0611 +from ganeti.rapi.client import UsesRapiClient def _FormatHeader(line, end=72): @@ -50,7 +56,7 @@ def _FormatHeader(line, end=72): """ line = "---- " + line + " " - line += "-" * (end-len(line)) + line += "-" * (end - len(line)) line = line.rstrip() return line @@ -66,7 +72,8 @@ def _DescriptionOf(fn): return desc.rstrip(".") -def RunTest(fn, *args): + +def RunTest(fn, *args, **kwargs): """Runs a test after printing a header. """ @@ -79,7 +86,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() @@ -87,7 +94,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 @@ -95,7 +102,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) @@ -121,6 +128,12 @@ def SetupCluster(rapi_user, rapi_secret): """ RunTestIf("create-cluster", qa_cluster.TestClusterInit, rapi_user, rapi_secret) + + # Test on empty cluster + RunTestIf("node-list", qa_node.TestNodeList) + RunTestIf("instance-list", qa_instance.TestInstanceList) + RunTestIf("job-list", qa_job.TestJobList) + RunTestIf("create-cluster", qa_node.TestNodeAddAll) if not qa_config.TestEnabled("create-cluster"): # consider the nodes are already there @@ -131,6 +144,14 @@ def SetupCluster(rapi_user, rapi_secret): # enable the watcher (unconditionally) RunTest(qa_daemon.TestResumeWatcher) + RunTestIf("node-list", qa_node.TestNodeList) + + # Test listing fields + RunTestIf("node-list", qa_node.TestNodeListFields) + RunTestIf("instance-list", qa_instance.TestInstanceListFields) + RunTestIf("job-list", qa_job.TestJobListFields) + RunTestIf("instance-export", qa_instance.TestBackupListFields) + RunTestIf("node-info", qa_node.TestNodeInfo) @@ -139,38 +160,66 @@ def RunClusterTests(): """ for test, fn in [ + ("create-cluster", qa_cluster.TestClusterInitDisk), ("cluster-renew-crypto", qa_cluster.TestClusterRenewCrypto), ("cluster-verify", qa_cluster.TestClusterVerify), ("cluster-reserved-lvs", qa_cluster.TestClusterReservedLvs), # TODO: add more cluster modify tests + ("cluster-modify", qa_cluster.TestClusterModifyEmpty), ("cluster-modify", qa_cluster.TestClusterModifyBe), + ("cluster-modify", qa_cluster.TestClusterModifyDisk), ("cluster-rename", qa_cluster.TestClusterRename), ("cluster-info", qa_cluster.TestClusterVersion), ("cluster-info", qa_cluster.TestClusterInfo), ("cluster-info", qa_cluster.TestClusterGetmaster), + ("cluster-redist-conf", qa_cluster.TestClusterRedistConf), ("cluster-copyfile", qa_cluster.TestClusterCopyfile), ("cluster-command", qa_cluster.TestClusterCommand), ("cluster-burnin", qa_cluster.TestClusterBurnin), ("cluster-master-failover", qa_cluster.TestClusterMasterFailover), + ("cluster-master-failover", + qa_cluster.TestClusterMasterFailoverWithDrainedQueue), + ("cluster-oob", qa_cluster.TestClusterOob), ("rapi", qa_rapi.TestVersion), ("rapi", qa_rapi.TestEmptyCluster), + ("rapi", qa_rapi.TestRapiQuery), ]: RunTestIf(test, fn) +def RunRepairDiskSizes(): + """Run the repair disk-sizes test. + + """ + RunTestIf("cluster-repair-disk-sizes", qa_cluster.TestClusterRepairDiskSizes) + + def RunOsTests(): """Runs all tests related to gnt-os. """ + if qa_config.TestEnabled("rapi"): + rapi_getos = qa_rapi.GetOperatingSystems + else: + rapi_getos = None + for fn in [ qa_os.TestOsList, qa_os.TestOsDiagnose, + ]: + RunTestIf("os", fn) + + for fn in [ qa_os.TestOsValid, qa_os.TestOsInvalid, qa_os.TestOsPartiallyValid, + ]: + RunTestIf("os", fn, rapi_getos) + + for fn in [ qa_os.TestOsModifyValid, qa_os.TestOsModifyInvalid, - qa_os.TestOsStates, + qa_os.TestOsStatesNonExisting, ]: RunTestIf("os", fn) @@ -180,8 +229,18 @@ def RunCommonInstanceTests(instance): """ RunTestIf("instance-shutdown", qa_instance.TestInstanceShutdown, instance) + RunTestIf(["instance-shutdown", "instance-console", "rapi"], + qa_rapi.TestRapiStoppedInstanceConsole, instance) + RunTestIf(["instance-shutdown", "instance-modify"], + qa_instance.TestInstanceStoppedModify, instance) RunTestIf("instance-shutdown", qa_instance.TestInstanceStartup, instance) + # Test shutdown/start via RAPI + RunTestIf(["instance-shutdown", "rapi"], + qa_rapi.TestRapiInstanceShutdown, instance) + RunTestIf(["instance-shutdown", "rapi"], + qa_rapi.TestRapiInstanceStartup, instance) + RunTestIf("instance-list", qa_instance.TestInstanceList) RunTestIf("instance-info", qa_instance.TestInstanceInfo, instance) @@ -191,31 +250,57 @@ def RunCommonInstanceTests(instance): qa_rapi.TestRapiInstanceModify, instance) RunTestIf("instance-console", qa_instance.TestInstanceConsole, instance) + RunTestIf(["instance-console", "rapi"], + qa_rapi.TestRapiInstanceConsole, instance) - RunTestIf("instance-reinstall", qa_instance.TestInstanceShutdown, instance) - RunTestIf("instance-reinstall", qa_instance.TestInstanceReinstall, instance) - RunTestIf("instance-reinstall", qa_instance.TestInstanceStartup, instance) + DOWN_TESTS = qa_config.Either([ + "instance-reinstall", + "instance-rename", + "instance-grow-disk", + ]) - RunTestIf("instance-reboot", qa_instance.TestInstanceReboot, instance) + # shutdown instance for any 'down' tests + RunTestIf(DOWN_TESTS, qa_instance.TestInstanceShutdown, instance) + + # now run the 'down' state tests + RunTestIf("instance-reinstall", qa_instance.TestInstanceReinstall, instance) + RunTestIf(["instance-reinstall", "rapi"], + qa_rapi.TestRapiInstanceReinstall, instance) - if qa_config.TestEnabled('instance-rename'): + if qa_config.TestEnabled("instance-rename"): rename_source = instance["name"] 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, rename_source, rename_target) - RunTest(qa_instance.TestInstanceRename, rename_target, rename_source) - RunTestIf("rapi", qa_rapi.TestRapiInstanceRename, rename_source, rename_target) - RunTestIf("rapi", qa_rapi.TestRapiInstanceRename, rename_target, rename_source) - RunTest(qa_instance.TestInstanceStartup, instance) + # perform instance rename to the same name + RunTest(qa_instance.TestInstanceRenameAndBack, + rename_source, rename_source) + RunTestIf("rapi", qa_rapi.TestRapiInstanceRenameAndBack, + rename_source, rename_source) + if rename_target is not None: + # perform instance rename to a different name, if we have one configured + RunTest(qa_instance.TestInstanceRenameAndBack, + rename_source, rename_target) + RunTestIf("rapi", qa_rapi.TestRapiInstanceRenameAndBack, + rename_source, rename_target) + + RunTestIf(["instance-grow-disk"], qa_instance.TestInstanceGrowDisk, instance) + + # and now start the instance again + RunTestIf(DOWN_TESTS, qa_instance.TestInstanceStartup, instance) + + RunTestIf("instance-reboot", qa_instance.TestInstanceReboot, instance) RunTestIf("tags", qa_tags.TestInstanceTags, instance) + RunTestIf("cluster-verify", qa_cluster.TestClusterVerify) + RunTestIf("rapi", qa_rapi.TestInstance, instance) + # Lists instances, too + RunTestIf("node-list", qa_node.TestNodeList) + + # Some jobs have been run, let's test listing them + RunTestIf("job-list", qa_job.TestJobList) + def RunCommonNodeTests(): """Run a few common node tests. @@ -223,14 +308,15 @@ def RunCommonNodeTests(): """ RunTestIf("node-volumes", qa_node.TestNodeVolumes) RunTestIf("node-storage", qa_node.TestNodeStorage) + RunTestIf("node-oob", qa_node.TestOutOfBand) def RunGroupListTests(): """Run tests for listing node groups. """ - RunTestIf("group-list", qa_group.TestGroupListDefaultFields) - RunTestIf("group-list", qa_group.TestGroupListAllFields) + RunTestIf("group-list", qa_group.TestGroupList) + RunTestIf("group-list", qa_group.TestGroupListFields) def RunGroupRwTests(): @@ -238,6 +324,12 @@ def RunGroupRwTests(): """ RunTestIf("group-rwops", qa_group.TestGroupAddRemoveRename) + RunTestIf("group-rwops", qa_group.TestGroupAddWithOptions) + RunTestIf("group-rwops", qa_group.TestGroupModify) + RunTestIf(["group-rwops", "rapi"], qa_rapi.TestRapiNodeGroups) + RunTestIf(["group-rwops", "tags"], qa_tags.TestGroupTags, + qa_group.GetDefaultGroup()) + def RunExportImportTests(instance, pnode, snode): """Tries to export and import the instance. @@ -247,7 +339,7 @@ def RunExportImportTests(instance, pnode, snode): otherwise None """ - if qa_config.TestEnabled('instance-export'): + if qa_config.TestEnabled("instance-export"): RunTest(qa_instance.TestInstanceExportNoTarget, instance) expnode = qa_config.AcquireNode(exclude=pnode) @@ -256,11 +348,13 @@ def RunExportImportTests(instance, pnode, snode): RunTest(qa_instance.TestBackupList, expnode) - if qa_config.TestEnabled('instance-import'): + if qa_config.TestEnabled("instance-import"): newinst = qa_config.AcquireInstance() try: - RunTest(qa_instance.TestInstanceImport, pnode, newinst, + RunTest(qa_instance.TestInstanceImport, newinst, pnode, expnode, name) + # Check if starting the instance works + RunTest(qa_instance.TestInstanceStartup, newinst) RunTest(qa_instance.TestInstanceRemove, newinst) finally: qa_config.ReleaseInstance(newinst) @@ -284,16 +378,16 @@ def RunExportImportTests(instance, pnode, snode): qa_config.ReleaseInstance(newinst) -def RunDaemonTests(instance, pnode): +def RunDaemonTests(instance): """Test the ganeti-watcher script. """ RunTest(qa_daemon.TestPauseWatcher) RunTestIf("instance-automatic-restart", - qa_daemon.TestInstanceAutomaticRestart, pnode, instance) + qa_daemon.TestInstanceAutomaticRestart, instance) RunTestIf("instance-consecutive-failures", - qa_daemon.TestInstanceConsecutiveFailures, pnode, instance) + qa_daemon.TestInstanceConsecutiveFailures, instance) RunTest(qa_daemon.TestResumeWatcher) @@ -303,14 +397,17 @@ def RunHardwareFailureTests(instance, pnode, snode): """ RunTestIf("instance-failover", qa_instance.TestInstanceFailover, instance) + RunTestIf(["instance-failover", "rapi"], + qa_rapi.TestRapiInstanceFailover, instance) RunTestIf("instance-migrate", qa_instance.TestInstanceMigrate, instance) RunTestIf(["instance-migrate", "rapi"], qa_rapi.TestRapiInstanceMigrate, instance) - if qa_config.TestEnabled('instance-replace-disks'): + if qa_config.TestEnabled("instance-replace-disks"): othernode = qa_config.AcquireNode(exclude=[pnode, snode]) try: + RunTestIf("rapi", qa_rapi.TestRapiInstanceReplaceDisks, instance) RunTest(qa_instance.TestReplaceDisks, instance, pnode, snode, othernode) finally: @@ -327,30 +424,10 @@ def RunHardwareFailureTests(instance, pnode, snode): pnode, snode) -@rapi.client.UsesRapiClient -def main(): - """Main program. +def RunQa(): + """Main QA body. """ - parser = optparse.OptionParser(usage="%prog [options] ") - 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() @@ -373,6 +450,7 @@ def main(): try: RunTestIf("node-readd", qa_node.TestNodeReadd, pnode) RunTestIf("node-modify", qa_node.TestNodeModify, pnode) + RunTestIf("delay", qa_cluster.TestDelay, pnode) finally: qa_config.ReleaseNode(pnode) @@ -387,21 +465,24 @@ def main(): for use_client in [True, False]: rapi_instance = RunTest(qa_rapi.TestRapiInstanceAdd, pnode, use_client) - RunCommonInstanceTests(rapi_instance) + if qa_config.TestEnabled("instance-plain-rapi-common-tests"): + RunCommonInstanceTests(rapi_instance) RunTest(qa_rapi.TestRapiInstanceRemove, rapi_instance, use_client) del rapi_instance - if qa_config.TestEnabled('instance-add-plain-disk'): + if qa_config.TestEnabled("instance-add-plain-disk"): instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode) RunCommonInstanceTests(instance) RunGroupListTests() + RunTestIf("cluster-epo", qa_cluster.TestClusterEpo) RunExportImportTests(instance, pnode, None) - RunDaemonTests(instance, pnode) + RunDaemonTests(instance) + RunRepairDiskSizes() RunTest(qa_instance.TestInstanceRemove, instance) del instance multinode_tests = [ - ('instance-add-drbd-disk', + ("instance-add-drbd-disk", qa_instance.TestInstanceAddWithDrbdDisk), ] @@ -410,20 +491,37 @@ def main(): snode = qa_config.AcquireNode(exclude=pnode) try: instance = RunTest(func, pnode, snode) - RunTestIf("cluster-verify", qa_cluster.TestClusterVerify) + RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, pnode) + RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, snode) RunCommonInstanceTests(instance) RunGroupListTests() - if qa_config.TestEnabled('instance-convert-disk'): + RunTest(qa_group.TestAssignNodesIncludingSplit, + constants.INITIAL_NODE_GROUP_NAME, + pnode["primary"], snode["primary"]) + 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) + RunRepairDiskSizes() RunTest(qa_instance.TestInstanceRemove, instance) del instance finally: qa_config.ReleaseNode(snode) + # Test removing instance with offline drbd secondary + if qa_config.TestEnabled("instance-remove-drbd-offline"): + snode = qa_config.AcquireNode(exclude=pnode) + instance = \ + qa_instance.TestInstanceAddWithDrbdDisk(pnode, snode) + try: + qa_node.MakeNodeOffline(snode, "yes") + RunTest(qa_instance.TestInstanceRemove, instance) + finally: + qa_node.MakeNodeOffline(snode, "no") + qa_config.ReleaseNode(snode) + if qa_config.TestEnabled(["instance-add-plain-disk", "instance-export"]): for shutdown in [False, True]: instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode) @@ -447,5 +545,40 @@ def main(): RunTestIf("cluster-destroy", qa_cluster.TestClusterDestroy) -if __name__ == '__main__': +@UsesRapiClient +def main(): + """Main program. + + """ + parser = optparse.OptionParser(usage="%prog [options] ") + 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) + + primary = qa_config.GetMasterNode()["primary"] + qa_utils.StartMultiplexer(primary) + print ("SSH command for primary node: %s" % + utils.ShellQuoteArgs(qa_utils.GetSSHCommand(primary, ""))) + print ("SSH command for other nodes: %s" % + utils.ShellQuoteArgs(qa_utils.GetSSHCommand("NODE", ""))) + try: + RunQa() + finally: + qa_utils.CloseMultiplexers() + +if __name__ == "__main__": main()