Merge remote branch 'origin/devel-2.1'
[ganeti-local] / qa / qa_cluster.py
1 #
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 """Cluster related QA tests.
23
24 """
25
26 import tempfile
27
28 from ganeti import constants
29 from ganeti import utils
30
31 import qa_config
32 import qa_utils
33 import qa_error
34
35 from qa_utils import AssertEqual, AssertNotEqual, StartSSH
36
37
38 def _RemoveFileFromAllNodes(filename):
39   """Removes a file from all nodes.
40
41   """
42   for node in qa_config.get('nodes'):
43     cmd = ['rm', '-f', filename]
44     AssertEqual(StartSSH(node['primary'],
45                          utils.ShellQuoteArgs(cmd)).wait(), 0)
46
47
48 def _CheckFileOnAllNodes(filename, content):
49   """Verifies the content of the given file on all nodes.
50
51   """
52   cmd = utils.ShellQuoteArgs(["cat", filename])
53   for node in qa_config.get('nodes'):
54     AssertEqual(qa_utils.GetCommandOutput(node['primary'], cmd),
55                 content)
56
57
58 def TestClusterInit():
59   """gnt-cluster init"""
60   master = qa_config.GetMasterNode()
61
62   cmd = ['gnt-cluster', 'init']
63
64   if master.get('secondary', None):
65     cmd.append('--secondary-ip=%s' % master['secondary'])
66
67   bridge = qa_config.get('bridge', None)
68   if bridge:
69     cmd.append('--bridge=%s' % bridge)
70     cmd.append('--master-netdev=%s' % bridge)
71
72   htype = qa_config.get('enabled-hypervisors', None)
73   if htype:
74     cmd.append('--enabled-hypervisors=%s' % htype)
75
76   cmd.append(qa_config.get('name'))
77
78   AssertEqual(StartSSH(master['primary'],
79                        utils.ShellQuoteArgs(cmd)).wait(), 0)
80
81
82 def TestClusterRename():
83   """gnt-cluster rename"""
84   master = qa_config.GetMasterNode()
85
86   cmd = ['gnt-cluster', 'rename', '-f']
87
88   original_name = qa_config.get('name')
89   rename_target = qa_config.get('rename', None)
90   if rename_target is None:
91     print qa_utils.FormatError('"rename" entry is missing')
92     return
93
94   cmd_1 = cmd + [rename_target]
95   cmd_2 = cmd + [original_name]
96
97   cmd_verify = ['gnt-cluster', 'verify']
98
99   AssertEqual(StartSSH(master['primary'],
100                        utils.ShellQuoteArgs(cmd_1)).wait(), 0)
101
102   AssertEqual(StartSSH(master['primary'],
103                        utils.ShellQuoteArgs(cmd_verify)).wait(), 0)
104
105   AssertEqual(StartSSH(master['primary'],
106                        utils.ShellQuoteArgs(cmd_2)).wait(), 0)
107
108   AssertEqual(StartSSH(master['primary'],
109                        utils.ShellQuoteArgs(cmd_verify)).wait(), 0)
110
111
112 def TestClusterVerify():
113   """gnt-cluster verify"""
114   master = qa_config.GetMasterNode()
115
116   cmd = ['gnt-cluster', 'verify']
117   AssertEqual(StartSSH(master['primary'],
118                        utils.ShellQuoteArgs(cmd)).wait(), 0)
119
120
121 def TestClusterInfo():
122   """gnt-cluster info"""
123   master = qa_config.GetMasterNode()
124
125   cmd = ['gnt-cluster', 'info']
126   AssertEqual(StartSSH(master['primary'],
127                        utils.ShellQuoteArgs(cmd)).wait(), 0)
128
129
130 def TestClusterGetmaster():
131   """gnt-cluster getmaster"""
132   master = qa_config.GetMasterNode()
133
134   cmd = ['gnt-cluster', 'getmaster']
135   AssertEqual(StartSSH(master['primary'],
136                        utils.ShellQuoteArgs(cmd)).wait(), 0)
137
138
139 def TestClusterVersion():
140   """gnt-cluster version"""
141   master = qa_config.GetMasterNode()
142
143   cmd = ['gnt-cluster', 'version']
144   AssertEqual(StartSSH(master['primary'],
145                        utils.ShellQuoteArgs(cmd)).wait(), 0)
146
147
148 def TestClusterRenewCrypto():
149   """gnt-cluster renew-crypto"""
150   master = qa_config.GetMasterNode()
151
152   # Conflicting options
153   cmd = ["gnt-cluster", "renew-crypto", "--force",
154          "--new-cluster-certificate", "--new-hmac-key",
155          "--new-rapi-certificate", "--rapi-certificate=/dev/null"]
156   AssertNotEqual(StartSSH(master["primary"],
157                           utils.ShellQuoteArgs(cmd)).wait(), 0)
158
159   # Invalid RAPI certificate
160   cmd = ["gnt-cluster", "renew-crypto", "--force",
161          "--rapi-certificate=/dev/null"]
162   AssertNotEqual(StartSSH(master["primary"],
163                           utils.ShellQuoteArgs(cmd)).wait(), 0)
164
165   # Custom RAPI certificate
166   fh = tempfile.NamedTemporaryFile()
167
168   # Ensure certificate doesn't cause "gnt-cluster verify" to complain
169   validity = constants.SSL_CERT_EXPIRATION_WARN * 3
170
171   utils.GenerateSelfSignedSslCert(fh.name, validity=validity)
172
173   tmpcert = qa_utils.UploadFile(master["primary"], fh.name)
174   try:
175     cmd = ["gnt-cluster", "renew-crypto", "--force",
176            "--rapi-certificate=%s" % tmpcert]
177     AssertEqual(StartSSH(master["primary"],
178                          utils.ShellQuoteArgs(cmd)).wait(), 0)
179   finally:
180     cmd = ["rm", "-f", tmpcert]
181     AssertEqual(StartSSH(master["primary"],
182                          utils.ShellQuoteArgs(cmd)).wait(), 0)
183
184   # Normal case
185   cmd = ["gnt-cluster", "renew-crypto", "--force",
186          "--new-cluster-certificate", "--new-hmac-key",
187          "--new-rapi-certificate"]
188   AssertEqual(StartSSH(master["primary"],
189                        utils.ShellQuoteArgs(cmd)).wait(), 0)
190
191
192 def TestClusterBurnin():
193   """Burnin"""
194   master = qa_config.GetMasterNode()
195
196   options = qa_config.get('options', {})
197   disk_template = options.get('burnin-disk-template', 'drbd')
198   parallel = options.get('burnin-in-parallel', False)
199   check_inst = options.get('burnin-check-instances', False)
200   do_rename = options.get('burnin-rename', '')
201
202   # Get as many instances as we need
203   instances = []
204   try:
205     try:
206       num = qa_config.get('options', {}).get('burnin-instances', 1)
207       for _ in range(0, num):
208         instances.append(qa_config.AcquireInstance())
209     except qa_error.OutOfInstancesError:
210       print "Not enough instances, continuing anyway."
211
212     if len(instances) < 1:
213       raise qa_error.Error("Burnin needs at least one instance")
214
215     script = qa_utils.UploadFile(master['primary'], '../tools/burnin')
216     try:
217       # Run burnin
218       cmd = [script,
219              '-p',
220              '--os=%s' % qa_config.get('os'),
221              '--disk-size=%s' % ",".join(qa_config.get('disk')),
222              '--disk-growth=%s' % ",".join(qa_config.get('disk-growth')),
223              '--disk-template=%s' % disk_template]
224       if parallel:
225         cmd.append('--parallel')
226       if check_inst:
227         cmd.append('--http-check')
228       if do_rename:
229         cmd.append('--rename=%s' % do_rename)
230       cmd += [inst['name'] for inst in instances]
231       AssertEqual(StartSSH(master['primary'],
232                            utils.ShellQuoteArgs(cmd)).wait(), 0)
233     finally:
234       cmd = ['rm', '-f', script]
235       AssertEqual(StartSSH(master['primary'],
236                            utils.ShellQuoteArgs(cmd)).wait(), 0)
237   finally:
238     for inst in instances:
239       qa_config.ReleaseInstance(inst)
240
241
242 def TestClusterMasterFailover():
243   """gnt-cluster masterfailover"""
244   master = qa_config.GetMasterNode()
245
246   failovermaster = qa_config.AcquireNode(exclude=master)
247   try:
248     cmd = ['gnt-cluster', 'masterfailover']
249     AssertEqual(StartSSH(failovermaster['primary'],
250                          utils.ShellQuoteArgs(cmd)).wait(), 0)
251
252     cmd = ['gnt-cluster', 'masterfailover']
253     AssertEqual(StartSSH(master['primary'],
254                          utils.ShellQuoteArgs(cmd)).wait(), 0)
255   finally:
256     qa_config.ReleaseNode(failovermaster)
257
258
259 def TestClusterCopyfile():
260   """gnt-cluster copyfile"""
261   master = qa_config.GetMasterNode()
262
263   uniqueid = utils.NewUUID()
264
265   # Create temporary file
266   f = tempfile.NamedTemporaryFile()
267   f.write(uniqueid)
268   f.flush()
269   f.seek(0)
270
271   # Upload file to master node
272   testname = qa_utils.UploadFile(master['primary'], f.name)
273   try:
274     # Copy file to all nodes
275     cmd = ['gnt-cluster', 'copyfile', testname]
276     AssertEqual(StartSSH(master['primary'],
277                          utils.ShellQuoteArgs(cmd)).wait(), 0)
278     _CheckFileOnAllNodes(testname, uniqueid)
279   finally:
280     _RemoveFileFromAllNodes(testname)
281
282
283 def TestClusterCommand():
284   """gnt-cluster command"""
285   master = qa_config.GetMasterNode()
286
287   uniqueid = utils.NewUUID()
288   rfile = "/tmp/gnt%s" % utils.NewUUID()
289   rcmd = utils.ShellQuoteArgs(['echo', '-n', uniqueid])
290   cmd = utils.ShellQuoteArgs(['gnt-cluster', 'command',
291                               "%s >%s" % (rcmd, rfile)])
292
293   try:
294     AssertEqual(StartSSH(master['primary'], cmd).wait(), 0)
295     _CheckFileOnAllNodes(rfile, uniqueid)
296   finally:
297     _RemoveFileFromAllNodes(rfile)
298
299
300 def TestClusterDestroy():
301   """gnt-cluster destroy"""
302   master = qa_config.GetMasterNode()
303
304   cmd = ['gnt-cluster', 'destroy', '--yes-do-it']
305   AssertEqual(StartSSH(master['primary'],
306                        utils.ShellQuoteArgs(cmd)).wait(), 0)