X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/5d6406723f5b7babc4249fec56d9bb793c12333f..21e2734ff4966735948b309d9664819f47810e64:/qa/ganeti-qa.py diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py index 270ecb4..9a207ce 100755 --- a/qa/ganeti-qa.py +++ b/qa/ganeti-qa.py @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/python -u # -# Copyright (C) 2007 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 @@ -21,188 +21,651 @@ """Script for doing QA on Ganeti. -You can create the required known_hosts file using ssh-keyscan. It's mandatory -to use the full name of a node (FQDN). For security reasons, verify the keys -before using them. -Example: ssh-keyscan -t rsa node{1,2,3,4}.example.com > known_hosts """ +# pylint: disable=C0103 +# due to invalid name + import sys -from datetime import datetime -from optparse import OptionParser +import datetime +import optparse import qa_cluster import qa_config import qa_daemon import qa_env +import qa_error +import qa_group import qa_instance import qa_node -import qa_other +import qa_os +import qa_job +import qa_rapi +import qa_tags +import qa_utils +from ganeti import utils +from ganeti import rapi # pylint: disable=W0611 +from ganeti import constants -def RunTest(fn, *args): - """Runs a test after printing a header. +import ganeti.rapi.client # pylint: disable=W0611 +from ganeti.rapi.client import UsesRapiClient + + +def _FormatHeader(line, end=72): + """Fill a line up to the end column. + + """ + line = "---- " + line + " " + line += "-" * (end - len(line)) + line = line.rstrip() + return line + + +def _DescriptionOf(fn): + """Computes the description of an item. """ if fn.__doc__: desc = fn.__doc__.splitlines()[0].strip() else: - desc = '%r' % fn + desc = "%r" % fn - now = str(datetime.now()) + return desc.rstrip(".") + + +def RunTest(fn, *args, **kwargs): + """Runs a test after printing a header. + + """ + + tstart = datetime.datetime.now() + + desc = _DescriptionOf(fn) print - print '---', now, ('-' * (55 - len(now))) - print desc - print '-' * 60 + print _FormatHeader("%s start %s" % (tstart, desc)) - return fn(*args) + try: + retval = fn(*args, **kwargs) + return retval + finally: + tstop = datetime.datetime.now() + tdelta = tstop - tstart + print _FormatHeader("%s time=%s %s" % (tstop, tdelta, desc)) -def main(): - """Main program. +def RunTestIf(testnames, fn, *args, **kwargs): + """Runs a test conditionally. + + @param testnames: either a single test name in the configuration + file, or a list of testnames (which will be AND-ed together) """ - parser = OptionParser(usage="%prog [options] " - "") - parser.add_option('--dry-run', dest='dry_run', - action="store_true", - help="Show what would be done") - 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 qa_config.TestEnabled(testnames): + RunTest(fn, *args, **kwargs) + else: + tstart = datetime.datetime.now() + desc = _DescriptionOf(fn) + print _FormatHeader("%s skipping %s, test(s) %s disabled" % + (tstart, desc, testnames)) + + +def RunEnvTests(): + """Run several environment tests. + + """ + RunTestIf("env", qa_env.TestSshConnection) + RunTestIf("env", qa_env.TestIcmpPing) + RunTestIf("env", 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 + + """ + 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 + qa_node.MarkNodeAddedAll() + + RunTestIf("test-jobqueue", qa_cluster.TestJobqueue) + + # 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) - if len(args) == 2: - (config_file, known_hosts_file) = args + RunTestIf("node-info", qa_node.TestNodeInfo) + + +def RunClusterTests(): + """Runs tests related to gnt-cluster. + + """ + 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: - parser.error("Not enough arguments.") + rapi_getos = None - 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) + for fn in [ + qa_os.TestOsList, + qa_os.TestOsDiagnose, + ]: + RunTestIf("os", fn) - qa_config.Load(config_file) + for fn in [ + qa_os.TestOsValid, + qa_os.TestOsInvalid, + qa_os.TestOsPartiallyValid, + ]: + RunTestIf("os", fn, rapi_getos) - RunTest(qa_other.TestUploadKnownHostsFile, known_hosts_file) + for fn in [ + qa_os.TestOsModifyValid, + qa_os.TestOsModifyInvalid, + qa_os.TestOsStatesNonExisting, + ]: + RunTestIf("os", fn) - if qa_config.TestEnabled('env'): - RunTest(qa_env.TestSshConnection) - RunTest(qa_env.TestIcmpPing) - RunTest(qa_env.TestGanetiCommands) - RunTest(qa_cluster.TestClusterInit) +def RunCommonInstanceTests(instance): + """Runs a few tests that are common to all disk types. - RunTest(qa_node.TestNodeAddAll) + """ + 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) - if qa_config.TestEnabled('cluster-verify'): - RunTest(qa_cluster.TestClusterVerify) + # Test shutdown/start via RAPI + RunTestIf(["instance-shutdown", "rapi"], + qa_rapi.TestRapiInstanceShutdown, instance) + RunTestIf(["instance-shutdown", "rapi"], + qa_rapi.TestRapiInstanceStartup, instance) - if qa_config.TestEnabled('cluster-info'): - RunTest(qa_cluster.TestClusterInfo) + RunTestIf("instance-list", qa_instance.TestInstanceList) - if qa_config.TestEnabled('cluster-copyfile'): - RunTest(qa_cluster.TestClusterCopyfile) + RunTestIf("instance-info", qa_instance.TestInstanceInfo, instance) - if qa_config.TestEnabled('node-info'): - RunTest(qa_node.TestNodeInfo) + RunTestIf("instance-modify", qa_instance.TestInstanceModify, instance) + RunTestIf(["instance-modify", "rapi"], + qa_rapi.TestRapiInstanceModify, instance) - if qa_config.TestEnabled('cluster-burnin'): - RunTest(qa_cluster.TestClusterBurnin) + RunTestIf("instance-console", qa_instance.TestInstanceConsole, instance) + RunTestIf(["instance-console", "rapi"], + qa_rapi.TestRapiInstanceConsole, instance) - if qa_config.TestEnabled('cluster-master-failover'): - RunTest(qa_cluster.TestClusterMasterFailover) + DOWN_TESTS = qa_config.Either([ + "instance-reinstall", + "instance-rename", + "instance-grow-disk", + ]) - node = qa_config.AcquireNode() - try: - if qa_config.TestEnabled('instance-add-plain-disk'): - instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, node) + # 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"): + tgt_instance = qa_config.AcquireInstance() + try: + rename_source = instance["name"] + rename_target = tgt_instance["name"] + # 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) + finally: + qa_config.ReleaseInstance(tgt_instance) + + 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. + + """ + 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.TestGroupList) + RunTestIf("group-list", qa_group.TestGroupListFields) - if qa_config.TestEnabled('instance-shutdown'): - RunTest(qa_instance.TestInstanceShutdown, instance) - RunTest(qa_instance.TestInstanceStartup, instance) - if qa_config.TestEnabled('instance-info'): - RunTest(qa_instance.TestInstanceInfo, instance) +def RunGroupRwTests(): + """Run tests for adding/removing/renaming groups. - if qa_config.TestEnabled('instance-automatic-restart'): - RunTest(qa_daemon.TestInstanceAutomaticRestart, node, instance) + """ + 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. + + @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) - if qa_config.TestEnabled('instance-consecutive-failures'): - RunTest(qa_daemon.TestInstanceConsecutiveFailures, node, instance) + RunTest(qa_instance.TestBackupList, expnode) - if qa_config.TestEnabled('instance-export'): - expnode = qa_config.AcquireNode(exclude=node) + if qa_config.TestEnabled("instance-import"): + newinst = qa_config.AcquireInstance() try: - name = RunTest(qa_instance.TestInstanceExport, instance, expnode) - - if qa_config.TestEnabled('instance-import'): - newinst = qa_config.AcquireInstance() - try: - RunTest(qa_instance.TestInstanceImport, node, newinst, - expnode, name) - RunTest(qa_instance.TestInstanceRemove, newinst) - finally: - qa_config.ReleaseInstance(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.ReleaseNode(expnode) + qa_config.ReleaseInstance(newinst) + finally: + qa_config.ReleaseNode(expnode) + + if qa_config.TestEnabled(["rapi", "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) - if qa_config.TestEnabled('node-volumes'): - RunTest(qa_node.TestNodeVolumes) - RunTest(qa_instance.TestInstanceRemove, instance) - del instance +def RunDaemonTests(instance): + """Test the ganeti-watcher script. - if qa_config.TestEnabled('instance-add-local-mirror-disk'): - instance = RunTest(qa_instance.TestInstanceAddWithLocalMirrorDisk, node) + """ + RunTest(qa_daemon.TestPauseWatcher) - if qa_config.TestEnabled('instance-shutdown'): - RunTest(qa_instance.TestInstanceShutdown, instance) - RunTest(qa_instance.TestInstanceStartup, instance) + RunTestIf("instance-automatic-restart", + qa_daemon.TestInstanceAutomaticRestart, instance) + RunTestIf("instance-consecutive-failures", + qa_daemon.TestInstanceConsecutiveFailures, instance) - if qa_config.TestEnabled('instance-info'): - RunTest(qa_instance.TestInstanceInfo, instance) + RunTest(qa_daemon.TestResumeWatcher) - if qa_config.TestEnabled('node-volumes'): - RunTest(qa_node.TestNodeVolumes) - RunTest(qa_instance.TestInstanceRemove, instance) - del instance +def RunSingleHomedHardwareFailureTests(instance, pnode): + """Test hardware failure recovery for single-homed instances. + + """ + if qa_config.TestEnabled("instance-recreate-disks"): + othernode = qa_config.AcquireNode(exclude=[pnode]) + try: + RunTest(qa_instance.TestRecreateDisks, + instance, pnode, None, [othernode]) + finally: + qa_config.ReleaseNode(othernode) + + +def RunHardwareFailureTests(instance, pnode, snode): + """Test cluster internal hardware failure recovery. - if qa_config.TestEnabled('instance-add-remote-raid-disk'): - node2 = qa_config.AcquireNode(exclude=node) + """ + 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"): + othernode = qa_config.AcquireNode(exclude=[pnode, snode]) + try: + RunTestIf("rapi", qa_rapi.TestRapiInstanceReplaceDisks, instance) + RunTest(qa_instance.TestReplaceDisks, + instance, pnode, snode, othernode) + finally: + qa_config.ReleaseNode(othernode) + + if qa_config.TestEnabled("instance-recreate-disks"): + othernode1 = qa_config.AcquireNode(exclude=[pnode, snode]) + try: + othernode2 = qa_config.AcquireNode(exclude=[pnode, snode, othernode1]) + except qa_error.OutOfNodesError: + # Let's reuse one of the nodes if the cluster is not big enough + othernode2 = pnode + try: + RunTest(qa_instance.TestRecreateDisks, + instance, pnode, snode, [othernode1, othernode2]) + finally: + qa_config.ReleaseNode(othernode1) + if othernode2 != pnode: + qa_config.ReleaseNode(othernode2) + + RunTestIf("node-evacuate", qa_node.TestNodeEvacuate, pnode, snode) + + RunTestIf("node-failover", qa_node.TestNodeFailover, pnode, snode) + + RunTestIf("instance-disk-failure", qa_instance.TestInstanceMasterDiskFailure, + instance, pnode, snode) + RunTestIf("instance-disk-failure", + qa_instance.TestInstanceSecondaryDiskFailure, instance, + pnode, snode) + + +def RunExclusiveStorageTests(): + """Test exclusive storage.""" + if not qa_config.TestEnabled("cluster-exclusive-storage"): + return + + node = qa_config.AcquireNode() + try: + old_es = qa_cluster.TestSetExclStorCluster(False) + qa_cluster.TestExclStorSingleNode(node) + + qa_cluster.TestSetExclStorCluster(True) + qa_cluster.TestExclStorSharedPv(node) + + if qa_config.TestEnabled("instance-add-plain-disk"): + # Make sure that the cluster doesn't have any pre-existing problem + qa_cluster.AssertClusterVerify() + instance1 = qa_instance.TestInstanceAddWithPlainDisk(node) + instance2 = qa_instance.TestInstanceAddWithPlainDisk(node) + # cluster-verify checks that disks are allocated correctly + qa_cluster.AssertClusterVerify() + qa_instance.TestInstanceRemove(instance1) + qa_instance.TestInstanceRemove(instance2) + if qa_config.TestEnabled("instance-add-drbd-disk"): + snode = qa_config.AcquireNode() try: - instance = RunTest(qa_instance.TestInstanceAddWithRemoteRaidDisk, - node, node2) + qa_cluster.TestSetExclStorCluster(False) + instance = qa_instance.TestInstanceAddWithDrbdDisk(node, snode) + qa_cluster.TestSetExclStorCluster(True) + exp_err = [constants.CV_EINSTANCEUNSUITABLENODE] + qa_cluster.AssertClusterVerify(fail=True, errors=exp_err) + qa_instance.TestInstanceRemove(instance) + finally: + qa_config.ReleaseNode(snode) + qa_cluster.TestSetExclStorCluster(old_es) + finally: + qa_config.ReleaseNode(node) - if qa_config.TestEnabled('instance-shutdown'): - RunTest(qa_instance.TestInstanceShutdown, instance) - RunTest(qa_instance.TestInstanceStartup, instance) - if qa_config.TestEnabled('instance-info'): - RunTest(qa_instance.TestInstanceInfo, instance) +def RunQa(): + """Main QA body. - if qa_config.TestEnabled('instance-failover'): - RunTest(qa_instance.TestInstanceFailover, instance) + """ + rapi_user = "ganeti-qa" + rapi_secret = utils.GenerateSecret() - if qa_config.TestEnabled('node-volumes'): - RunTest(qa_node.TestNodeVolumes) + RunEnvTests() + SetupCluster(rapi_user, rapi_secret) - RunTest(qa_instance.TestInstanceRemove, instance) - del instance + # Load RAPI certificate + qa_rapi.Setup(rapi_user, rapi_secret) + + RunClusterTests() + RunOsTests() + + RunTestIf("tags", qa_tags.TestClusterTags) + + RunCommonNodeTests() + RunGroupListTests() + RunGroupRwTests() + + # The master shouldn't be readded or put offline; "delay" needs a non-master + # node to test + pnode = qa_config.AcquireNode(exclude=qa_config.GetMasterNode()) + 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) + + pnode = qa_config.AcquireNode() + try: + RunTestIf("tags", 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) + 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"): + instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode) + RunCommonInstanceTests(instance) + RunGroupListTests() + RunTestIf("cluster-epo", qa_cluster.TestClusterEpo) + RunExportImportTests(instance, pnode, None) + RunDaemonTests(instance) + RunRepairDiskSizes() + RunSingleHomedHardwareFailureTests(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) + RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, pnode) + RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, snode) + RunCommonInstanceTests(instance) + RunGroupListTests() + RunTestIf("group-rwops", 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) + + finally: + qa_config.ReleaseNode(pnode) + + # Test removing instance with offline drbd secondary + if qa_config.TestEnabled("instance-remove-drbd-offline"): + # Make sure the master is not put offline + snode = qa_config.AcquireNode(exclude=qa_config.GetMasterNode()) + try: + pnode = qa_config.AcquireNode(exclude=snode) + try: + instance = qa_instance.TestInstanceAddWithDrbdDisk(pnode, snode) + qa_node.MakeNodeOffline(snode, "yes") + try: + RunTest(qa_instance.TestInstanceRemove, instance) + finally: + qa_node.MakeNodeOffline(snode, "no") finally: - qa_config.ReleaseNode(node2) + qa_config.ReleaseNode(pnode) + finally: + qa_config.ReleaseNode(snode) + + pnode = qa_config.AcquireNode() + try: + if qa_config.TestEnabled(["instance-add-plain-disk", "instance-export"]): + for shutdown in [False, True]: + instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode) + expnode = qa_config.AcquireNode(exclude=pnode) + try: + if shutdown: + # Stop instance before exporting and removing it + RunTest(qa_instance.TestInstanceShutdown, instance) + RunTest(qa_instance.TestInstanceExportWithRemove, instance, expnode) + RunTest(qa_instance.TestBackupList, expnode) + finally: + qa_config.ReleaseNode(expnode) + del expnode + del instance finally: - qa_config.ReleaseNode(node) + qa_config.ReleaseNode(pnode) + + RunExclusiveStorageTests() + + RunTestIf("create-cluster", qa_node.TestNodeRemoveAll) - RunTest(qa_node.TestNodeRemoveAll) + RunTestIf("cluster-destroy", qa_cluster.TestClusterDestroy) - if qa_config.TestEnabled('cluster-destroy'): - RunTest(qa_cluster.TestClusterDestroy) +@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__': +if __name__ == "__main__": main()