Rename OpExportInstance and LUExportInstance
[ganeti-local] / qa / qa_cluster.py
1 #
2 #
3
4 # Copyright (C) 2007, 2010, 2011 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 import os.path
28
29 from ganeti import constants
30 from ganeti import utils
31
32 import qa_config
33 import qa_utils
34 import qa_error
35
36 from qa_utils import AssertEqual, AssertCommand
37
38
39 def _RemoveFileFromAllNodes(filename):
40   """Removes a file from all nodes.
41
42   """
43   for node in qa_config.get("nodes"):
44     AssertCommand(["rm", "-f", filename], node=node)
45
46
47 def _CheckFileOnAllNodes(filename, content):
48   """Verifies the content of the given file on all nodes.
49
50   """
51   cmd = utils.ShellQuoteArgs(["cat", filename])
52   for node in qa_config.get("nodes"):
53     AssertEqual(qa_utils.GetCommandOutput(node["primary"], cmd), content)
54
55
56 def TestClusterInit(rapi_user, rapi_secret):
57   """gnt-cluster init"""
58   master = qa_config.GetMasterNode()
59
60   rapi_dir = os.path.dirname(constants.RAPI_USERS_FILE)
61
62   # First create the RAPI credentials
63   fh = tempfile.NamedTemporaryFile()
64   try:
65     fh.write("%s %s write\n" % (rapi_user, rapi_secret))
66     fh.flush()
67
68     tmpru = qa_utils.UploadFile(master["primary"], fh.name)
69     try:
70       AssertCommand(["mkdir", "-p", rapi_dir])
71       AssertCommand(["mv", tmpru, constants.RAPI_USERS_FILE])
72     finally:
73       AssertCommand(["rm", "-f", tmpru])
74   finally:
75     fh.close()
76
77   # Initialize cluster
78   cmd = ['gnt-cluster', 'init']
79
80   cmd.append("--primary-ip-version=%d" %
81              qa_config.get("primary_ip_version", 4))
82
83   if master.get('secondary', None):
84     cmd.append('--secondary-ip=%s' % master['secondary'])
85
86   bridge = qa_config.get('bridge', None)
87   if bridge:
88     cmd.append('--bridge=%s' % bridge)
89     cmd.append('--master-netdev=%s' % bridge)
90
91   htype = qa_config.get('enabled-hypervisors', None)
92   if htype:
93     cmd.append('--enabled-hypervisors=%s' % htype)
94
95   cmd.append(qa_config.get('name'))
96
97   AssertCommand(cmd)
98
99
100 def TestClusterRename():
101   """gnt-cluster rename"""
102   cmd = ['gnt-cluster', 'rename', '-f']
103
104   original_name = qa_config.get('name')
105   rename_target = qa_config.get('rename', None)
106   if rename_target is None:
107     print qa_utils.FormatError('"rename" entry is missing')
108     return
109
110   cmd_verify = ['gnt-cluster', 'verify']
111
112   for data in [
113     cmd + [rename_target],
114     cmd_verify,
115     cmd + [original_name],
116     cmd_verify,
117     ]:
118     AssertCommand(data)
119
120
121 def TestClusterOob():
122   """out-of-band framework"""
123   oob_path_exists = "/tmp/ganeti-qa-oob-does-exist-%s" % utils.NewUUID()
124
125   AssertCommand(["gnt-cluster", "verify"])
126   AssertCommand(["gnt-cluster", "modify", "--node-parameters",
127                  "oob_program=/tmp/ganeti-qa-oob-does-not-exist-%s" %
128                  utils.NewUUID()])
129
130   AssertCommand(["gnt-cluster", "verify"], fail=True)
131
132   AssertCommand(["touch", oob_path_exists])
133   AssertCommand(["chmod", "0400", oob_path_exists])
134   AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
135
136   try:
137     AssertCommand(["gnt-cluster", "modify", "--node-parameters",
138                    "oob_program=%s" % oob_path_exists])
139
140     AssertCommand(["gnt-cluster", "verify"], fail=True)
141
142     AssertCommand(["chmod", "0500", oob_path_exists])
143     AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
144
145     AssertCommand(["gnt-cluster", "verify"])
146   finally:
147     AssertCommand(["gnt-cluster", "command", "rm", oob_path_exists])
148
149   AssertCommand(["gnt-cluster", "modify", "--node-parameters",
150                  "oob_program="])
151
152
153 def TestClusterVerify():
154   """gnt-cluster verify"""
155   AssertCommand(["gnt-cluster", "verify"])
156
157
158 def TestJobqueue():
159   """gnt-debug test-jobqueue"""
160   AssertCommand(["gnt-debug", "test-jobqueue"])
161
162
163 def TestClusterReservedLvs():
164   """gnt-cluster reserved lvs"""
165   CVERIFY = ["gnt-cluster", "verify"]
166   for fail, cmd in [
167     (False, CVERIFY),
168     (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
169     (False, ["lvcreate", "-L1G", "-nqa-test", "xenvg"]),
170     (True,  CVERIFY),
171     (False, ["gnt-cluster", "modify", "--reserved-lvs",
172              "xenvg/qa-test,.*/other-test"]),
173     (False, CVERIFY),
174     (False, ["gnt-cluster", "modify", "--reserved-lvs", ".*/qa-.*"]),
175     (False, CVERIFY),
176     (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
177     (True,  CVERIFY),
178     (False, ["lvremove", "-f", "xenvg/qa-test"]),
179     (False, CVERIFY),
180     ]:
181     AssertCommand(cmd, fail=fail)
182
183
184 def TestClusterModifyBe():
185   """gnt-cluster modify -B"""
186   for fail, cmd in [
187     # mem
188     (False, ["gnt-cluster", "modify", "-B", "memory=256"]),
189     (False, ["sh", "-c", "gnt-cluster info|grep '^ *memory: 256$'"]),
190     (True,  ["gnt-cluster", "modify", "-B", "memory=a"]),
191     (False, ["gnt-cluster", "modify", "-B", "memory=128"]),
192     (False, ["sh", "-c", "gnt-cluster info|grep '^ *memory: 128$'"]),
193     # vcpus
194     (False, ["gnt-cluster", "modify", "-B", "vcpus=4"]),
195     (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 4$'"]),
196     (True,  ["gnt-cluster", "modify", "-B", "vcpus=a"]),
197     (False, ["gnt-cluster", "modify", "-B", "vcpus=1"]),
198     (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 1$'"]),
199     # auto_balance
200     (False, ["gnt-cluster", "modify", "-B", "auto_balance=False"]),
201     (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: False$'"]),
202     (True,  ["gnt-cluster", "modify", "-B", "auto_balance=1"]),
203     (False, ["gnt-cluster", "modify", "-B", "auto_balance=True"]),
204     (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: True$'"]),
205     ]:
206     AssertCommand(cmd, fail=fail)
207
208
209 def TestClusterInfo():
210   """gnt-cluster info"""
211   AssertCommand(["gnt-cluster", "info"])
212
213
214 def TestClusterGetmaster():
215   """gnt-cluster getmaster"""
216   AssertCommand(["gnt-cluster", "getmaster"])
217
218
219 def TestClusterVersion():
220   """gnt-cluster version"""
221   AssertCommand(["gnt-cluster", "version"])
222
223
224 def TestClusterRenewCrypto():
225   """gnt-cluster renew-crypto"""
226   master = qa_config.GetMasterNode()
227
228   # Conflicting options
229   cmd = ["gnt-cluster", "renew-crypto", "--force",
230          "--new-cluster-certificate", "--new-confd-hmac-key"]
231   conflicting = [
232     ["--new-rapi-certificate", "--rapi-certificate=/dev/null"],
233     ["--new-cluster-domain-secret", "--cluster-domain-secret=/dev/null"],
234     ]
235   for i in conflicting:
236     AssertCommand(cmd+i, fail=True)
237
238   # Invalid RAPI certificate
239   cmd = ["gnt-cluster", "renew-crypto", "--force",
240          "--rapi-certificate=/dev/null"]
241   AssertCommand(cmd, fail=True)
242
243   rapi_cert_backup = qa_utils.BackupFile(master["primary"],
244                                          constants.RAPI_CERT_FILE)
245   try:
246     # Custom RAPI certificate
247     fh = tempfile.NamedTemporaryFile()
248
249     # Ensure certificate doesn't cause "gnt-cluster verify" to complain
250     validity = constants.SSL_CERT_EXPIRATION_WARN * 3
251
252     utils.GenerateSelfSignedSslCert(fh.name, validity=validity)
253
254     tmpcert = qa_utils.UploadFile(master["primary"], fh.name)
255     try:
256       AssertCommand(["gnt-cluster", "renew-crypto", "--force",
257                      "--rapi-certificate=%s" % tmpcert])
258     finally:
259       AssertCommand(["rm", "-f", tmpcert])
260
261     # Custom cluster domain secret
262     cds_fh = tempfile.NamedTemporaryFile()
263     cds_fh.write(utils.GenerateSecret())
264     cds_fh.write("\n")
265     cds_fh.flush()
266
267     tmpcds = qa_utils.UploadFile(master["primary"], cds_fh.name)
268     try:
269       AssertCommand(["gnt-cluster", "renew-crypto", "--force",
270                      "--cluster-domain-secret=%s" % tmpcds])
271     finally:
272       AssertCommand(["rm", "-f", tmpcds])
273
274     # Normal case
275     AssertCommand(["gnt-cluster", "renew-crypto", "--force",
276                    "--new-cluster-certificate", "--new-confd-hmac-key",
277                    "--new-rapi-certificate", "--new-cluster-domain-secret"])
278
279     # Restore RAPI certificate
280     AssertCommand(["gnt-cluster", "renew-crypto", "--force",
281                    "--rapi-certificate=%s" % rapi_cert_backup])
282   finally:
283     AssertCommand(["rm", "-f", rapi_cert_backup])
284
285
286 def TestClusterBurnin():
287   """Burnin"""
288   master = qa_config.GetMasterNode()
289
290   options = qa_config.get('options', {})
291   disk_template = options.get('burnin-disk-template', 'drbd')
292   parallel = options.get('burnin-in-parallel', False)
293   check_inst = options.get('burnin-check-instances', False)
294   do_rename = options.get('burnin-rename', '')
295   do_reboot = options.get('burnin-reboot', True)
296   reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
297
298   # Get as many instances as we need
299   instances = []
300   try:
301     try:
302       num = qa_config.get('options', {}).get('burnin-instances', 1)
303       for _ in range(0, num):
304         instances.append(qa_config.AcquireInstance())
305     except qa_error.OutOfInstancesError:
306       print "Not enough instances, continuing anyway."
307
308     if len(instances) < 1:
309       raise qa_error.Error("Burnin needs at least one instance")
310
311     script = qa_utils.UploadFile(master['primary'], '../tools/burnin')
312     try:
313       # Run burnin
314       cmd = [script,
315              '--os=%s' % qa_config.get('os'),
316              '--disk-size=%s' % ",".join(qa_config.get('disk')),
317              '--disk-growth=%s' % ",".join(qa_config.get('disk-growth')),
318              '--disk-template=%s' % disk_template]
319       if parallel:
320         cmd.append('--parallel')
321         cmd.append('--early-release')
322       if check_inst:
323         cmd.append('--http-check')
324       if do_rename:
325         cmd.append('--rename=%s' % do_rename)
326       if not do_reboot:
327         cmd.append('--no-reboot')
328       else:
329         cmd.append('--reboot-types=%s' % ",".join(reboot_types))
330       cmd += [inst['name'] for inst in instances]
331       AssertCommand(cmd)
332     finally:
333       AssertCommand(["rm", "-f", script])
334
335   finally:
336     for inst in instances:
337       qa_config.ReleaseInstance(inst)
338
339
340 def TestClusterMasterFailover():
341   """gnt-cluster master-failover"""
342   master = qa_config.GetMasterNode()
343   failovermaster = qa_config.AcquireNode(exclude=master)
344
345   cmd = ["gnt-cluster", "master-failover"]
346   try:
347     AssertCommand(cmd, node=failovermaster)
348     AssertCommand(cmd, node=master)
349   finally:
350     qa_config.ReleaseNode(failovermaster)
351
352
353 def TestClusterCopyfile():
354   """gnt-cluster copyfile"""
355   master = qa_config.GetMasterNode()
356
357   uniqueid = utils.NewUUID()
358
359   # Create temporary file
360   f = tempfile.NamedTemporaryFile()
361   f.write(uniqueid)
362   f.flush()
363   f.seek(0)
364
365   # Upload file to master node
366   testname = qa_utils.UploadFile(master['primary'], f.name)
367   try:
368     # Copy file to all nodes
369     AssertCommand(["gnt-cluster", "copyfile", testname])
370     _CheckFileOnAllNodes(testname, uniqueid)
371   finally:
372     _RemoveFileFromAllNodes(testname)
373
374
375 def TestClusterCommand():
376   """gnt-cluster command"""
377   uniqueid = utils.NewUUID()
378   rfile = "/tmp/gnt%s" % utils.NewUUID()
379   rcmd = utils.ShellQuoteArgs(['echo', '-n', uniqueid])
380   cmd = utils.ShellQuoteArgs(['gnt-cluster', 'command',
381                               "%s >%s" % (rcmd, rfile)])
382
383   try:
384     AssertCommand(cmd)
385     _CheckFileOnAllNodes(rfile, uniqueid)
386   finally:
387     _RemoveFileFromAllNodes(rfile)
388
389
390 def TestClusterDestroy():
391   """gnt-cluster destroy"""
392   AssertCommand(["gnt-cluster", "destroy", "--yes-do-it"])