4 # Copyright (C) 2007, 2008 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for doing QA on Ganeti.
24 You can create the required known_hosts file using ssh-keyscan. It's mandatory
25 to use the full name of a node (FQDN). For security reasons, verify the keys
27 Example: ssh-keyscan -t rsa node{1,2,3,4}.example.com > known_hosts
31 from datetime import datetime
32 from optparse import OptionParser
47 def RunTest(fn, *args):
48 """Runs a test after printing a header.
52 desc = fn.__doc__.splitlines()[0].strip()
56 now = str(datetime.now())
59 print '---', now, ('-' * (55 - len(now)))
67 """Run several environment tests.
70 if not qa_config.TestEnabled('env'):
73 RunTest(qa_env.TestSshConnection)
74 RunTest(qa_env.TestIcmpPing)
75 RunTest(qa_env.TestGanetiCommands)
79 """Initializes the cluster.
82 RunTest(qa_cluster.TestClusterInit)
83 RunTest(qa_node.TestNodeAddAll)
84 if qa_config.TestEnabled('node-info'):
85 RunTest(qa_node.TestNodeInfo)
88 def RunClusterTests():
89 """Runs tests related to gnt-cluster.
92 if qa_config.TestEnabled('cluster-verify'):
93 RunTest(qa_cluster.TestClusterVerify)
95 if qa_config.TestEnabled('cluster-rename'):
96 RunTest(qa_cluster.TestClusterRename)
98 if qa_config.TestEnabled('cluster-info'):
99 RunTest(qa_cluster.TestClusterVersion)
100 RunTest(qa_cluster.TestClusterInfo)
101 RunTest(qa_cluster.TestClusterGetmaster)
103 if qa_config.TestEnabled('cluster-copyfile'):
104 RunTest(qa_cluster.TestClusterCopyfile)
106 if qa_config.TestEnabled('cluster-command'):
107 RunTest(qa_cluster.TestClusterCommand)
109 if qa_config.TestEnabled('cluster-burnin'):
110 RunTest(qa_cluster.TestClusterBurnin)
112 if qa_config.TestEnabled('cluster-master-failover'):
113 RunTest(qa_cluster.TestClusterMasterFailover)
115 if qa_rapi.Enabled():
116 RunTest(qa_rapi.TestVersion)
117 RunTest(qa_rapi.TestEmptyCluster)
121 """Runs all tests related to gnt-os.
124 if not qa_config.TestEnabled('os'):
127 RunTest(qa_os.TestOsList)
128 RunTest(qa_os.TestOsDiagnose)
129 RunTest(qa_os.TestOsValid)
130 RunTest(qa_os.TestOsInvalid)
131 RunTest(qa_os.TestOsPartiallyValid)
134 def RunCommonInstanceTests(instance):
135 """Runs a few tests that are common to all disk types.
138 if qa_config.TestEnabled('instance-shutdown'):
139 RunTest(qa_instance.TestInstanceShutdown, instance)
140 RunTest(qa_instance.TestInstanceStartup, instance)
142 if qa_config.TestEnabled('instance-list'):
143 RunTest(qa_instance.TestInstanceList)
145 if qa_config.TestEnabled('instance-info'):
146 RunTest(qa_instance.TestInstanceInfo, instance)
148 if qa_config.TestEnabled('instance-modify'):
149 RunTest(qa_instance.TestInstanceModify, instance)
151 if qa_config.TestEnabled('instance-reinstall'):
152 RunTest(qa_instance.TestInstanceShutdown, instance)
153 RunTest(qa_instance.TestInstanceReinstall, instance)
154 RunTest(qa_instance.TestInstanceStartup, instance)
156 if qa_config.TestEnabled('instance-reboot'):
157 RunTest(qa_instance.TestInstanceReboot, instance)
159 if qa_config.TestEnabled('tags'):
160 RunTest(qa_tags.TestInstanceTags, instance)
162 if qa_config.TestEnabled('node-volumes'):
163 RunTest(qa_node.TestNodeVolumes)
165 if qa_rapi.Enabled():
166 RunTest(qa_rapi.TestInstance, instance)
169 def RunExportImportTests(instance, pnode):
170 """Tries to export and import the instance.
173 if qa_config.TestEnabled('instance-export'):
174 expnode = qa_config.AcquireNode(exclude=pnode)
176 name = RunTest(qa_instance.TestInstanceExport, instance, expnode)
178 RunTest(qa_instance.TestBackupList, expnode)
180 if qa_config.TestEnabled('instance-import'):
181 newinst = qa_config.AcquireInstance()
183 RunTest(qa_instance.TestInstanceImport, pnode, newinst,
185 RunTest(qa_instance.TestInstanceRemove, newinst)
187 qa_config.ReleaseInstance(newinst)
189 qa_config.ReleaseNode(expnode)
192 def RunDaemonTests(instance, pnode):
193 """Test the ganeti-watcher script.
196 automatic_restart = \
197 qa_config.TestEnabled('instance-automatic-restart')
198 consecutive_failures = \
199 qa_config.TestEnabled('instance-consecutive-failures')
201 if automatic_restart or consecutive_failures:
202 qa_daemon.PrintCronWarning()
204 if automatic_restart:
205 RunTest(qa_daemon.TestInstanceAutomaticRestart, pnode, instance)
207 if consecutive_failures:
208 RunTest(qa_daemon.TestInstanceConsecutiveFailures, pnode, instance)
211 def RunHardwareFailureTests(instance, pnode, snode, is_drbd):
212 """Test cluster internal hardware failure recovery.
215 if qa_config.TestEnabled('instance-migrate'):
216 RunTest(qa_instance.TestInstanceMigrate, instance)
218 if qa_config.TestEnabled('instance-failover'):
219 RunTest(qa_instance.TestInstanceFailover, instance)
221 if qa_config.TestEnabled('instance-replace-disks'):
222 othernode = qa_config.AcquireNode(exclude=[pnode, snode])
224 RunTest(qa_instance.TestReplaceDisks,
225 instance, pnode, snode, othernode, is_drbd)
227 qa_config.ReleaseNode(othernode)
229 if qa_config.TestEnabled('node-evacuate'):
230 RunTest(qa_node.TestNodeEvacuate, pnode, snode)
232 if qa_config.TestEnabled('node-failover'):
233 RunTest(qa_node.TestNodeFailover, pnode, snode)
235 if qa_config.TestEnabled('instance-disk-failure'):
236 RunTest(qa_instance.TestInstanceMasterDiskFailure,
237 instance, pnode, snode)
238 RunTest(qa_instance.TestInstanceSecondaryDiskFailure,
239 instance, pnode, snode)
246 parser = OptionParser(usage="%prog [options] <config-file>"
247 " <known-hosts-file>")
248 parser.add_option('--dry-run', dest='dry_run',
250 help="Show what would be done")
251 parser.add_option('--yes-do-it', dest='yes_do_it',
253 help="Really execute the tests")
254 (qa_config.options, args) = parser.parse_args()
257 (config_file, known_hosts_file) = args
259 parser.error("Not enough arguments.")
261 if not qa_config.options.yes_do_it:
262 print ("Executing this script irreversibly destroys any Ganeti\n"
263 "configuration on all nodes involved. If you really want\n"
264 "to start testing, supply the --yes-do-it option.")
267 qa_config.Load(config_file)
270 qa_rapi.PrintRemoteAPIWarning()
272 RunTest(qa_other.UploadKnownHostsFile, known_hosts_file)
279 if qa_config.TestEnabled('tags'):
280 RunTest(qa_tags.TestClusterTags)
282 if qa_config.TestEnabled('node-readd'):
283 master = qa_config.GetMasterNode()
284 pnode = qa_config.AcquireNode(exclude=master)
286 RunTest(qa_node.TestNodeReadd, pnode)
288 qa_config.ReleaseNode(pnode)
290 pnode = qa_config.AcquireNode()
292 if qa_config.TestEnabled('tags'):
293 RunTest(qa_tags.TestNodeTags, pnode)
295 if qa_rapi.Enabled():
296 RunTest(qa_rapi.TestNode, pnode)
298 if qa_config.TestEnabled('instance-add-plain-disk'):
299 instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
300 RunCommonInstanceTests(instance)
301 if qa_config.TestEnabled('instance-grow-disk'):
302 RunTest(qa_instance.TestInstanceGrowDisk, instance, False)
303 RunExportImportTests(instance, pnode)
304 RunDaemonTests(instance, pnode)
305 RunTest(qa_instance.TestInstanceRemove, instance)
308 if qa_config.TestEnabled('instance-add-local-mirror-disk'):
309 instance = RunTest(qa_instance.TestInstanceAddWithLocalMirrorDisk, pnode)
310 if qa_config.TestEnabled('instance-grow-disk'):
311 RunTest(qa_instance.TestInstanceGrowDisk, instance, True)
312 RunCommonInstanceTests(instance)
313 RunExportImportTests(instance, pnode)
314 RunTest(qa_instance.TestInstanceRemove, instance)
318 ('instance-add-remote-raid-disk',
319 qa_instance.TestInstanceAddWithRemoteRaidDisk,
321 ('instance-add-drbd-disk',
322 qa_instance.TestInstanceAddWithDrbdDisk,
326 for name, func, is_drbd in multinode_tests:
327 if qa_config.TestEnabled(name):
328 snode = qa_config.AcquireNode(exclude=pnode)
330 instance = RunTest(func, pnode, snode)
331 RunCommonInstanceTests(instance)
332 if qa_config.TestEnabled('instance-grow-disk'):
333 RunTest(qa_instance.TestInstanceGrowDisk, instance, False)
334 RunExportImportTests(instance, pnode)
335 RunHardwareFailureTests(instance, pnode, snode, is_drbd)
336 RunTest(qa_instance.TestInstanceRemove, instance)
339 qa_config.ReleaseNode(snode)
342 qa_config.ReleaseNode(pnode)
344 RunTest(qa_node.TestNodeRemoveAll)
346 if qa_config.TestEnabled('cluster-destroy'):
347 RunTest(qa_cluster.TestClusterDestroy)
350 if __name__ == '__main__':