Make rpc.call_lv_list() VG-aware
[ganeti-local] / qa / qa_cluster.py
1 #
2 #
3
4 # Copyright (C) 2007, 2010 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 TestClusterVerify():
122   """gnt-cluster verify"""
123   AssertCommand(["gnt-cluster", "verify"])
124
125
126 def TestJobqueue():
127   """gnt-debug test-jobqueue"""
128   AssertCommand(["gnt-debug", "test-jobqueue"])
129
130
131 def TestClusterReservedLvs():
132   """gnt-cluster reserved lvs"""
133   CVERIFY = ["gnt-cluster", "verify"]
134   for fail, cmd in [
135     (False, CVERIFY),
136     (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
137     (False, ["lvcreate", "-L1G", "-nqa-test", "xenvg"]),
138     (True,  CVERIFY),
139     (False, ["gnt-cluster", "modify", "--reserved-lvs",
140              "xenvg/qa-test,.*/other-test"]),
141     (False, CVERIFY),
142     (False, ["gnt-cluster", "modify", "--reserved-lvs", ".*/qa-.*"]),
143     (False, CVERIFY),
144     (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
145     (True,  CVERIFY),
146     (False, ["lvremove", "-f", "xenvg/qa-test"]),
147     (False, CVERIFY),
148     ]:
149     AssertCommand(cmd, fail=fail)
150
151
152 def TestClusterModifyBe():
153   """gnt-cluster modify -B"""
154   for fail, cmd in [
155     # mem
156     (False, ["gnt-cluster", "modify", "-B", "memory=256"]),
157     (False, ["sh", "-c", "gnt-cluster info|grep '^ *memory: 256$'"]),
158     (True,  ["gnt-cluster", "modify", "-B", "memory=a"]),
159     (False, ["gnt-cluster", "modify", "-B", "memory=128"]),
160     (False, ["sh", "-c", "gnt-cluster info|grep '^ *memory: 128$'"]),
161     # vcpus
162     (False, ["gnt-cluster", "modify", "-B", "vcpus=4"]),
163     (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 4$'"]),
164     (True,  ["gnt-cluster", "modify", "-B", "vcpus=a"]),
165     (False, ["gnt-cluster", "modify", "-B", "vcpus=1"]),
166     (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 1$'"]),
167     # auto_balance
168     (False, ["gnt-cluster", "modify", "-B", "auto_balance=False"]),
169     (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: False$'"]),
170     (True,  ["gnt-cluster", "modify", "-B", "auto_balance=1"]),
171     (False, ["gnt-cluster", "modify", "-B", "auto_balance=True"]),
172     (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: True$'"]),
173     ]:
174     AssertCommand(cmd, fail=fail)
175
176
177 def TestClusterInfo():
178   """gnt-cluster info"""
179   AssertCommand(["gnt-cluster", "info"])
180
181
182 def TestClusterGetmaster():
183   """gnt-cluster getmaster"""
184   AssertCommand(["gnt-cluster", "getmaster"])
185
186
187 def TestClusterVersion():
188   """gnt-cluster version"""
189   AssertCommand(["gnt-cluster", "version"])
190
191
192 def TestClusterRenewCrypto():
193   """gnt-cluster renew-crypto"""
194   master = qa_config.GetMasterNode()
195
196   # Conflicting options
197   cmd = ["gnt-cluster", "renew-crypto", "--force",
198          "--new-cluster-certificate", "--new-confd-hmac-key"]
199   conflicting = [
200     ["--new-rapi-certificate", "--rapi-certificate=/dev/null"],
201     ["--new-cluster-domain-secret", "--cluster-domain-secret=/dev/null"],
202     ]
203   for i in conflicting:
204     AssertCommand(cmd+i, fail=True)
205
206   # Invalid RAPI certificate
207   cmd = ["gnt-cluster", "renew-crypto", "--force",
208          "--rapi-certificate=/dev/null"]
209   AssertCommand(cmd, fail=True)
210
211   rapi_cert_backup = qa_utils.BackupFile(master["primary"],
212                                          constants.RAPI_CERT_FILE)
213   try:
214     # Custom RAPI certificate
215     fh = tempfile.NamedTemporaryFile()
216
217     # Ensure certificate doesn't cause "gnt-cluster verify" to complain
218     validity = constants.SSL_CERT_EXPIRATION_WARN * 3
219
220     utils.GenerateSelfSignedSslCert(fh.name, validity=validity)
221
222     tmpcert = qa_utils.UploadFile(master["primary"], fh.name)
223     try:
224       AssertCommand(["gnt-cluster", "renew-crypto", "--force",
225                      "--rapi-certificate=%s" % tmpcert])
226     finally:
227       AssertCommand(["rm", "-f", tmpcert])
228
229     # Custom cluster domain secret
230     cds_fh = tempfile.NamedTemporaryFile()
231     cds_fh.write(utils.GenerateSecret())
232     cds_fh.write("\n")
233     cds_fh.flush()
234
235     tmpcds = qa_utils.UploadFile(master["primary"], cds_fh.name)
236     try:
237       AssertCommand(["gnt-cluster", "renew-crypto", "--force",
238                      "--cluster-domain-secret=%s" % tmpcds])
239     finally:
240       AssertCommand(["rm", "-f", tmpcds])
241
242     # Normal case
243     AssertCommand(["gnt-cluster", "renew-crypto", "--force",
244                    "--new-cluster-certificate", "--new-confd-hmac-key",
245                    "--new-rapi-certificate", "--new-cluster-domain-secret"])
246
247     # Restore RAPI certificate
248     AssertCommand(["gnt-cluster", "renew-crypto", "--force",
249                    "--rapi-certificate=%s" % rapi_cert_backup])
250   finally:
251     AssertCommand(["rm", "-f", rapi_cert_backup])
252
253
254 def TestClusterBurnin():
255   """Burnin"""
256   master = qa_config.GetMasterNode()
257
258   options = qa_config.get('options', {})
259   disk_template = options.get('burnin-disk-template', 'drbd')
260   parallel = options.get('burnin-in-parallel', False)
261   check_inst = options.get('burnin-check-instances', False)
262   do_rename = options.get('burnin-rename', '')
263   do_reboot = options.get('burnin-reboot', True)
264   reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
265
266   # Get as many instances as we need
267   instances = []
268   try:
269     try:
270       num = qa_config.get('options', {}).get('burnin-instances', 1)
271       for _ in range(0, num):
272         instances.append(qa_config.AcquireInstance())
273     except qa_error.OutOfInstancesError:
274       print "Not enough instances, continuing anyway."
275
276     if len(instances) < 1:
277       raise qa_error.Error("Burnin needs at least one instance")
278
279     script = qa_utils.UploadFile(master['primary'], '../tools/burnin')
280     try:
281       # Run burnin
282       cmd = [script,
283              '--os=%s' % qa_config.get('os'),
284              '--disk-size=%s' % ",".join(qa_config.get('disk')),
285              '--disk-growth=%s' % ",".join(qa_config.get('disk-growth')),
286              '--disk-template=%s' % disk_template]
287       if parallel:
288         cmd.append('--parallel')
289         cmd.append('--early-release')
290       if check_inst:
291         cmd.append('--http-check')
292       if do_rename:
293         cmd.append('--rename=%s' % do_rename)
294       if not do_reboot:
295         cmd.append('--no-reboot')
296       else:
297         cmd.append('--reboot-types=%s' % ",".join(reboot_types))
298       cmd += [inst['name'] for inst in instances]
299       AssertCommand(cmd)
300     finally:
301       AssertCommand(["rm", "-f", script])
302
303   finally:
304     for inst in instances:
305       qa_config.ReleaseInstance(inst)
306
307
308 def TestClusterMasterFailover():
309   """gnt-cluster master-failover"""
310   master = qa_config.GetMasterNode()
311   failovermaster = qa_config.AcquireNode(exclude=master)
312
313   cmd = ["gnt-cluster", "master-failover"]
314   try:
315     AssertCommand(cmd, node=failovermaster)
316     AssertCommand(cmd, node=master)
317   finally:
318     qa_config.ReleaseNode(failovermaster)
319
320
321 def TestClusterCopyfile():
322   """gnt-cluster copyfile"""
323   master = qa_config.GetMasterNode()
324
325   uniqueid = utils.NewUUID()
326
327   # Create temporary file
328   f = tempfile.NamedTemporaryFile()
329   f.write(uniqueid)
330   f.flush()
331   f.seek(0)
332
333   # Upload file to master node
334   testname = qa_utils.UploadFile(master['primary'], f.name)
335   try:
336     # Copy file to all nodes
337     AssertCommand(["gnt-cluster", "copyfile", testname])
338     _CheckFileOnAllNodes(testname, uniqueid)
339   finally:
340     _RemoveFileFromAllNodes(testname)
341
342
343 def TestClusterCommand():
344   """gnt-cluster command"""
345   uniqueid = utils.NewUUID()
346   rfile = "/tmp/gnt%s" % utils.NewUUID()
347   rcmd = utils.ShellQuoteArgs(['echo', '-n', uniqueid])
348   cmd = utils.ShellQuoteArgs(['gnt-cluster', 'command',
349                               "%s >%s" % (rcmd, rfile)])
350
351   try:
352     AssertCommand(cmd)
353     _CheckFileOnAllNodes(rfile, uniqueid)
354   finally:
355     _RemoveFileFromAllNodes(rfile)
356
357
358 def TestClusterDestroy():
359   """gnt-cluster destroy"""
360   AssertCommand(["gnt-cluster", "destroy", "--yes-do-it"])