qa: enable early release during parallel burnin
[ganeti-local] / qa / ganeti-qa.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2007 Google Inc.
5 #
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.
10 #
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.
15 #
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
19 # 02110-1301, USA.
20
21
22 """Script for doing QA on Ganeti.
23
24 """
25
26 import sys
27 import datetime
28 import optparse
29
30 import qa_cluster
31 import qa_config
32 import qa_daemon
33 import qa_env
34 import qa_instance
35 import qa_node
36 import qa_os
37 import qa_rapi
38 import qa_tags
39 import qa_utils
40
41 from ganeti import utils
42
43
44 def RunTest(fn, *args):
45   """Runs a test after printing a header.
46
47   """
48   if fn.__doc__:
49     desc = fn.__doc__.splitlines()[0].strip()
50   else:
51     desc = '%r' % fn
52
53   now = str(datetime.datetime.now())
54
55   print
56   print '---', now, ('-' * (55 - len(now)))
57   print desc
58   print '-' * 60
59
60   return fn(*args)
61
62
63 def RunEnvTests():
64   """Run several environment tests.
65
66   """
67   if not qa_config.TestEnabled('env'):
68     return
69
70   RunTest(qa_env.TestSshConnection)
71   RunTest(qa_env.TestIcmpPing)
72   RunTest(qa_env.TestGanetiCommands)
73
74
75 def SetupCluster(rapi_user, rapi_secret):
76   """Initializes the cluster.
77
78   @param rapi_user: Login user for RAPI
79   @param rapi_secret: Login secret for RAPI
80
81   """
82   if qa_config.TestEnabled('create-cluster'):
83     RunTest(qa_cluster.TestClusterInit, rapi_user, rapi_secret)
84     RunTest(qa_node.TestNodeAddAll)
85   else:
86     # consider the nodes are already there
87     qa_node.MarkNodeAddedAll()
88   if qa_config.TestEnabled('node-info'):
89     RunTest(qa_node.TestNodeInfo)
90
91
92 def RunClusterTests():
93   """Runs tests related to gnt-cluster.
94
95   """
96   if qa_config.TestEnabled("cluster-renew-crypto"):
97     RunTest(qa_cluster.TestClusterRenewCrypto)
98
99   if qa_config.TestEnabled('cluster-verify'):
100     RunTest(qa_cluster.TestClusterVerify)
101
102   if qa_config.TestEnabled('cluster-rename'):
103     RunTest(qa_cluster.TestClusterRename)
104
105   if qa_config.TestEnabled('cluster-info'):
106     RunTest(qa_cluster.TestClusterVersion)
107     RunTest(qa_cluster.TestClusterInfo)
108     RunTest(qa_cluster.TestClusterGetmaster)
109
110   if qa_config.TestEnabled('cluster-copyfile'):
111     RunTest(qa_cluster.TestClusterCopyfile)
112
113   if qa_config.TestEnabled('cluster-command'):
114     RunTest(qa_cluster.TestClusterCommand)
115
116   if qa_config.TestEnabled('cluster-burnin'):
117     RunTest(qa_cluster.TestClusterBurnin)
118
119   if qa_config.TestEnabled('cluster-master-failover'):
120     RunTest(qa_cluster.TestClusterMasterFailover)
121
122   if qa_rapi.Enabled():
123     RunTest(qa_rapi.TestVersion)
124     RunTest(qa_rapi.TestEmptyCluster)
125
126
127 def RunOsTests():
128   """Runs all tests related to gnt-os.
129
130   """
131   if not qa_config.TestEnabled('os'):
132     return
133
134   RunTest(qa_os.TestOsList)
135   RunTest(qa_os.TestOsDiagnose)
136   RunTest(qa_os.TestOsValid)
137   RunTest(qa_os.TestOsInvalid)
138   RunTest(qa_os.TestOsPartiallyValid)
139   RunTest(qa_os.TestOsModifyValid)
140   RunTest(qa_os.TestOsModifyInvalid)
141
142
143 def RunCommonInstanceTests(instance):
144   """Runs a few tests that are common to all disk types.
145
146   """
147   if qa_config.TestEnabled('instance-shutdown'):
148     RunTest(qa_instance.TestInstanceShutdown, instance)
149     RunTest(qa_instance.TestInstanceStartup, instance)
150
151   if qa_config.TestEnabled('instance-list'):
152     RunTest(qa_instance.TestInstanceList)
153
154   if qa_config.TestEnabled('instance-info'):
155     RunTest(qa_instance.TestInstanceInfo, instance)
156
157   if qa_config.TestEnabled('instance-modify'):
158     RunTest(qa_instance.TestInstanceModify, instance)
159
160   if qa_config.TestEnabled('instance-console'):
161     RunTest(qa_instance.TestInstanceConsole, instance)
162
163   if qa_config.TestEnabled('instance-reinstall'):
164     RunTest(qa_instance.TestInstanceShutdown, instance)
165     RunTest(qa_instance.TestInstanceReinstall, instance)
166     RunTest(qa_instance.TestInstanceStartup, instance)
167
168   if qa_config.TestEnabled('instance-reboot'):
169     RunTest(qa_instance.TestInstanceReboot, instance)
170
171   if qa_config.TestEnabled('instance-rename'):
172     RunTest(qa_instance.TestInstanceShutdown, instance)
173     RunTest(qa_instance.TestInstanceRename, instance)
174     RunTest(qa_instance.TestInstanceStartup, instance)
175
176   if qa_config.TestEnabled('tags'):
177     RunTest(qa_tags.TestInstanceTags, instance)
178
179   if qa_config.TestEnabled('node-volumes'):
180     RunTest(qa_node.TestNodeVolumes)
181
182   if qa_config.TestEnabled("node-storage"):
183     RunTest(qa_node.TestNodeStorage)
184
185   if qa_rapi.Enabled():
186     RunTest(qa_rapi.TestInstance, instance)
187
188
189 def RunExportImportTests(instance, pnode):
190   """Tries to export and import the instance.
191
192   """
193   if qa_config.TestEnabled('instance-export'):
194     expnode = qa_config.AcquireNode(exclude=pnode)
195     try:
196       name = RunTest(qa_instance.TestInstanceExport, instance, expnode)
197
198       RunTest(qa_instance.TestBackupList, expnode)
199
200       if qa_config.TestEnabled('instance-import'):
201         newinst = qa_config.AcquireInstance()
202         try:
203           RunTest(qa_instance.TestInstanceImport, pnode, newinst,
204                   expnode, name)
205           RunTest(qa_instance.TestInstanceRemove, newinst)
206         finally:
207           qa_config.ReleaseInstance(newinst)
208     finally:
209       qa_config.ReleaseNode(expnode)
210
211
212 def RunDaemonTests(instance, pnode):
213   """Test the ganeti-watcher script.
214
215   """
216   automatic_restart = \
217     qa_config.TestEnabled('instance-automatic-restart')
218   consecutive_failures = \
219     qa_config.TestEnabled('instance-consecutive-failures')
220
221   if automatic_restart or consecutive_failures:
222     qa_daemon.PrintCronWarning()
223
224     if automatic_restart:
225       RunTest(qa_daemon.TestInstanceAutomaticRestart, pnode, instance)
226
227     if consecutive_failures:
228       RunTest(qa_daemon.TestInstanceConsecutiveFailures, pnode, instance)
229
230
231 def RunHardwareFailureTests(instance, pnode, snode):
232   """Test cluster internal hardware failure recovery.
233
234   """
235   if qa_config.TestEnabled('instance-failover'):
236     RunTest(qa_instance.TestInstanceFailover, instance)
237
238   if qa_config.TestEnabled('instance-replace-disks'):
239     othernode = qa_config.AcquireNode(exclude=[pnode, snode])
240     try:
241       RunTest(qa_instance.TestReplaceDisks,
242               instance, pnode, snode, othernode)
243     finally:
244       qa_config.ReleaseNode(othernode)
245
246   if qa_config.TestEnabled('node-evacuate'):
247     RunTest(qa_node.TestNodeEvacuate, pnode, snode)
248
249   if qa_config.TestEnabled('node-failover'):
250     RunTest(qa_node.TestNodeFailover, pnode, snode)
251
252   if qa_config.TestEnabled('instance-disk-failure'):
253     RunTest(qa_instance.TestInstanceMasterDiskFailure,
254             instance, pnode, snode)
255     RunTest(qa_instance.TestInstanceSecondaryDiskFailure,
256             instance, pnode, snode)
257
258
259 def main():
260   """Main program.
261
262   """
263   parser = optparse.OptionParser(usage="%prog [options] <config-file>")
264   parser.add_option('--yes-do-it', dest='yes_do_it',
265       action="store_true",
266       help="Really execute the tests")
267   (qa_config.options, args) = parser.parse_args()
268
269   if len(args) == 1:
270     (config_file, ) = args
271   else:
272     parser.error("Wrong number of arguments.")
273
274   if not qa_config.options.yes_do_it:
275     print ("Executing this script irreversibly destroys any Ganeti\n"
276            "configuration on all nodes involved. If you really want\n"
277            "to start testing, supply the --yes-do-it option.")
278     sys.exit(1)
279
280   qa_config.Load(config_file)
281
282   rapi_user = "ganeti-qa"
283   rapi_secret = utils.GenerateSecret()
284   qa_rapi.OpenerFactory.SetCredentials(rapi_user, rapi_secret)
285
286   RunEnvTests()
287   SetupCluster(rapi_user, rapi_secret)
288   RunClusterTests()
289   RunOsTests()
290
291   if qa_config.TestEnabled('tags'):
292     RunTest(qa_tags.TestClusterTags)
293
294   if qa_config.TestEnabled('node-readd'):
295     master = qa_config.GetMasterNode()
296     pnode = qa_config.AcquireNode(exclude=master)
297     try:
298       RunTest(qa_node.TestNodeReadd, pnode)
299     finally:
300       qa_config.ReleaseNode(pnode)
301
302   pnode = qa_config.AcquireNode()
303   try:
304     if qa_config.TestEnabled('tags'):
305       RunTest(qa_tags.TestNodeTags, pnode)
306
307     if qa_rapi.Enabled():
308       RunTest(qa_rapi.TestNode, pnode)
309
310     if qa_config.TestEnabled('instance-add-plain-disk'):
311       instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
312       RunCommonInstanceTests(instance)
313       RunExportImportTests(instance, pnode)
314       RunDaemonTests(instance, pnode)
315       RunTest(qa_instance.TestInstanceRemove, instance)
316       del instance
317
318     multinode_tests = [
319       ('instance-add-drbd-disk',
320        qa_instance.TestInstanceAddWithDrbdDisk),
321     ]
322
323     for name, func in multinode_tests:
324       if qa_config.TestEnabled(name):
325         snode = qa_config.AcquireNode(exclude=pnode)
326         try:
327           instance = RunTest(func, pnode, snode)
328           RunCommonInstanceTests(instance)
329           if qa_config.TestEnabled('instance-convert-disk'):
330             RunTest(qa_instance.TestInstanceConvertDisk, instance, snode)
331           RunExportImportTests(instance, pnode)
332           RunHardwareFailureTests(instance, pnode, snode)
333           RunTest(qa_instance.TestInstanceRemove, instance)
334           del instance
335         finally:
336           qa_config.ReleaseNode(snode)
337
338   finally:
339     qa_config.ReleaseNode(pnode)
340
341   if qa_config.TestEnabled('create-cluster'):
342     RunTest(qa_node.TestNodeRemoveAll)
343
344   if qa_config.TestEnabled('cluster-destroy'):
345     RunTest(qa_cluster.TestClusterDestroy)
346
347
348 if __name__ == '__main__':
349   main()