Statistics
| Branch: | Tag: | Revision:

root / qa / qa_cluster.py @ c2a0947d

History | View | Annotate | Download (14.3 kB)

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 compat
31
from ganeti import utils
32

    
33
import qa_config
34
import qa_utils
35
import qa_error
36

    
37
from qa_utils import AssertEqual, AssertCommand, GetCommandOutput
38

    
39

    
40
#: cluster verify command
41
_CLUSTER_VERIFY = ["gnt-cluster", "verify"]
42

    
43
def _RemoveFileFromAllNodes(filename):
44
  """Removes a file from all nodes.
45

46
  """
47
  for node in qa_config.get("nodes"):
48
    AssertCommand(["rm", "-f", filename], node=node)
49

    
50

    
51
def _CheckFileOnAllNodes(filename, content):
52
  """Verifies the content of the given file on all nodes.
53

54
  """
55
  cmd = utils.ShellQuoteArgs(["cat", filename])
56
  for node in qa_config.get("nodes"):
57
    AssertEqual(qa_utils.GetCommandOutput(node["primary"], cmd), content)
58

    
59

    
60
def TestClusterInit(rapi_user, rapi_secret):
61
  """gnt-cluster init"""
62
  master = qa_config.GetMasterNode()
63

    
64
  rapi_dir = os.path.dirname(constants.RAPI_USERS_FILE)
65

    
66
  # First create the RAPI credentials
67
  fh = tempfile.NamedTemporaryFile()
68
  try:
69
    fh.write("%s %s write\n" % (rapi_user, rapi_secret))
70
    fh.flush()
71

    
72
    tmpru = qa_utils.UploadFile(master["primary"], fh.name)
73
    try:
74
      AssertCommand(["mkdir", "-p", rapi_dir])
75
      AssertCommand(["mv", tmpru, constants.RAPI_USERS_FILE])
76
    finally:
77
      AssertCommand(["rm", "-f", tmpru])
78
  finally:
79
    fh.close()
80

    
81
  # Initialize cluster
82
  cmd = ["gnt-cluster", "init"]
83

    
84
  cmd.append("--primary-ip-version=%d" %
85
             qa_config.get("primary_ip_version", 4))
86

    
87
  if master.get("secondary", None):
88
    cmd.append("--secondary-ip=%s" % master["secondary"])
89

    
90
  bridge = qa_config.get("bridge", None)
91
  if bridge:
92
    cmd.append("--bridge=%s" % bridge)
93
    cmd.append("--master-netdev=%s" % bridge)
94

    
95
  htype = qa_config.get("enabled-hypervisors", None)
96
  if htype:
97
    cmd.append("--enabled-hypervisors=%s" % htype)
98

    
99
  cmd.append(qa_config.get("name"))
100

    
101
  AssertCommand(cmd)
102

    
103

    
104
def TestClusterRename():
105
  """gnt-cluster rename"""
106
  cmd = ["gnt-cluster", "rename", "-f"]
107

    
108
  original_name = qa_config.get("name")
109
  rename_target = qa_config.get("rename", None)
110
  if rename_target is None:
111
    print qa_utils.FormatError('"rename" entry is missing')
112
    return
113

    
114
  for data in [
115
    cmd + [rename_target],
116
    _CLUSTER_VERIFY,
117
    cmd + [original_name],
118
    _CLUSTER_VERIFY,
119
    ]:
120
    AssertCommand(data)
121

    
122

    
123
def TestClusterOob():
124
  """out-of-band framework"""
125
  oob_path_exists = "/tmp/ganeti-qa-oob-does-exist-%s" % utils.NewUUID()
126

    
127
  AssertCommand(_CLUSTER_VERIFY)
128
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
129
                 "oob_program=/tmp/ganeti-qa-oob-does-not-exist-%s" %
130
                 utils.NewUUID()])
131

    
132
  AssertCommand(_CLUSTER_VERIFY, fail=True)
133

    
134
  AssertCommand(["touch", oob_path_exists])
135
  AssertCommand(["chmod", "0400", oob_path_exists])
136
  AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
137

    
138
  try:
139
    AssertCommand(["gnt-cluster", "modify", "--node-parameters",
140
                   "oob_program=%s" % oob_path_exists])
141

    
142
    AssertCommand(_CLUSTER_VERIFY, fail=True)
143

    
144
    AssertCommand(["chmod", "0500", oob_path_exists])
145
    AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
146

    
147
    AssertCommand(_CLUSTER_VERIFY)
148
  finally:
149
    AssertCommand(["gnt-cluster", "command", "rm", oob_path_exists])
150

    
151
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
152
                 "oob_program="])
153

    
154

    
155
def TestClusterEpo():
156
  """gnt-cluster epo"""
157
  master = qa_config.GetMasterNode()
158

    
159
  # Assert that OOB is unavailable for all nodes
160
  result_output = GetCommandOutput(master["primary"],
161
                                   "gnt-node list --verbose --no-header -o"
162
                                   " powered")
163
  AssertEqual(compat.all(powered == "(unavail)"
164
                         for powered in result_output.splitlines()), True)
165

    
166
  # Conflicting
167
  AssertCommand(["gnt-cluster", "epo", "--groups", "--all"], fail=True)
168
  # --all doesn't expect arguments
169
  AssertCommand(["gnt-cluster", "epo", "--all", "some_arg"], fail=True)
170

    
171
  # Unless --all is given master is not allowed to be in the list
172
  AssertCommand(["gnt-cluster", "epo", "-f", master["primary"]], fail=True)
173

    
174
  # This shouldn't fail
175
  AssertCommand(["gnt-cluster", "epo", "-f", "--all"])
176

    
177
  # All instances should have been stopped now
178
  result_output = GetCommandOutput(master["primary"],
179
                                   "gnt-instance list --no-header -o status")
180
  AssertEqual(compat.all(status == "ADMIN_down"
181
                         for status in result_output.splitlines()), True)
182

    
183
  # Now start everything again
184
  AssertCommand(["gnt-cluster", "epo", "--on", "-f", "--all"])
185

    
186
  # All instances should have been started now
187
  result_output = GetCommandOutput(master["primary"],
188
                                   "gnt-instance list --no-header -o status")
189
  AssertEqual(compat.all(status == "running"
190
                         for status in result_output.splitlines()), True)
191

    
192

    
193
def TestClusterVerify():
194
  """gnt-cluster verify"""
195
  AssertCommand(_CLUSTER_VERIFY)
196
  AssertCommand(["gnt-cluster", "verify-disks"])
197

    
198

    
199
def TestJobqueue():
200
  """gnt-debug test-jobqueue"""
201
  AssertCommand(["gnt-debug", "test-jobqueue"])
202

    
203

    
204
def TestClusterReservedLvs():
205
  """gnt-cluster reserved lvs"""
206
  for fail, cmd in [
207
    (False, _CLUSTER_VERIFY),
208
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
209
    (False, ["lvcreate", "-L1G", "-nqa-test", "xenvg"]),
210
    (True,  _CLUSTER_VERIFY),
211
    (False, ["gnt-cluster", "modify", "--reserved-lvs",
212
             "xenvg/qa-test,.*/other-test"]),
213
    (False, _CLUSTER_VERIFY),
214
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ".*/qa-.*"]),
215
    (False, _CLUSTER_VERIFY),
216
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
217
    (True,  _CLUSTER_VERIFY),
218
    (False, ["lvremove", "-f", "xenvg/qa-test"]),
219
    (False, _CLUSTER_VERIFY),
220
    ]:
221
    AssertCommand(cmd, fail=fail)
222

    
223

    
224
def TestClusterModifyBe():
225
  """gnt-cluster modify -B"""
226
  for fail, cmd in [
227
    # mem
228
    (False, ["gnt-cluster", "modify", "-B", "memory=256"]),
229
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *memory: 256$'"]),
230
    (True,  ["gnt-cluster", "modify", "-B", "memory=a"]),
231
    (False, ["gnt-cluster", "modify", "-B", "memory=128"]),
232
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *memory: 128$'"]),
233
    # vcpus
234
    (False, ["gnt-cluster", "modify", "-B", "vcpus=4"]),
235
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 4$'"]),
236
    (True,  ["gnt-cluster", "modify", "-B", "vcpus=a"]),
237
    (False, ["gnt-cluster", "modify", "-B", "vcpus=1"]),
238
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 1$'"]),
239
    # auto_balance
240
    (False, ["gnt-cluster", "modify", "-B", "auto_balance=False"]),
241
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: False$'"]),
242
    (True,  ["gnt-cluster", "modify", "-B", "auto_balance=1"]),
243
    (False, ["gnt-cluster", "modify", "-B", "auto_balance=True"]),
244
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: True$'"]),
245
    ]:
246
    AssertCommand(cmd, fail=fail)
247

    
248

    
249
def TestClusterInfo():
250
  """gnt-cluster info"""
251
  AssertCommand(["gnt-cluster", "info"])
252

    
253

    
254
def TestClusterRedistConf():
255
  """gnt-cluster redist-conf"""
256
  AssertCommand(["gnt-cluster", "redist-conf"])
257

    
258

    
259
def TestClusterGetmaster():
260
  """gnt-cluster getmaster"""
261
  AssertCommand(["gnt-cluster", "getmaster"])
262

    
263

    
264
def TestClusterVersion():
265
  """gnt-cluster version"""
266
  AssertCommand(["gnt-cluster", "version"])
267

    
268

    
269
def TestClusterRenewCrypto():
270
  """gnt-cluster renew-crypto"""
271
  master = qa_config.GetMasterNode()
272

    
273
  # Conflicting options
274
  cmd = ["gnt-cluster", "renew-crypto", "--force",
275
         "--new-cluster-certificate", "--new-confd-hmac-key"]
276
  conflicting = [
277
    ["--new-rapi-certificate", "--rapi-certificate=/dev/null"],
278
    ["--new-cluster-domain-secret", "--cluster-domain-secret=/dev/null"],
279
    ]
280
  for i in conflicting:
281
    AssertCommand(cmd+i, fail=True)
282

    
283
  # Invalid RAPI certificate
284
  cmd = ["gnt-cluster", "renew-crypto", "--force",
285
         "--rapi-certificate=/dev/null"]
286
  AssertCommand(cmd, fail=True)
287

    
288
  rapi_cert_backup = qa_utils.BackupFile(master["primary"],
289
                                         constants.RAPI_CERT_FILE)
290
  try:
291
    # Custom RAPI certificate
292
    fh = tempfile.NamedTemporaryFile()
293

    
294
    # Ensure certificate doesn't cause "gnt-cluster verify" to complain
295
    validity = constants.SSL_CERT_EXPIRATION_WARN * 3
296

    
297
    utils.GenerateSelfSignedSslCert(fh.name, validity=validity)
298

    
299
    tmpcert = qa_utils.UploadFile(master["primary"], fh.name)
300
    try:
301
      AssertCommand(["gnt-cluster", "renew-crypto", "--force",
302
                     "--rapi-certificate=%s" % tmpcert])
303
    finally:
304
      AssertCommand(["rm", "-f", tmpcert])
305

    
306
    # Custom cluster domain secret
307
    cds_fh = tempfile.NamedTemporaryFile()
308
    cds_fh.write(utils.GenerateSecret())
309
    cds_fh.write("\n")
310
    cds_fh.flush()
311

    
312
    tmpcds = qa_utils.UploadFile(master["primary"], cds_fh.name)
313
    try:
314
      AssertCommand(["gnt-cluster", "renew-crypto", "--force",
315
                     "--cluster-domain-secret=%s" % tmpcds])
316
    finally:
317
      AssertCommand(["rm", "-f", tmpcds])
318

    
319
    # Normal case
320
    AssertCommand(["gnt-cluster", "renew-crypto", "--force",
321
                   "--new-cluster-certificate", "--new-confd-hmac-key",
322
                   "--new-rapi-certificate", "--new-cluster-domain-secret"])
323

    
324
    # Restore RAPI certificate
325
    AssertCommand(["gnt-cluster", "renew-crypto", "--force",
326
                   "--rapi-certificate=%s" % rapi_cert_backup])
327
  finally:
328
    AssertCommand(["rm", "-f", rapi_cert_backup])
329

    
330

    
331
def TestClusterBurnin():
332
  """Burnin"""
333
  master = qa_config.GetMasterNode()
334

    
335
  options = qa_config.get("options", {})
336
  disk_template = options.get("burnin-disk-template", "drbd")
337
  parallel = options.get("burnin-in-parallel", False)
338
  check_inst = options.get("burnin-check-instances", False)
339
  do_rename = options.get("burnin-rename", "")
340
  do_reboot = options.get("burnin-reboot", True)
341
  reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
342

    
343
  # Get as many instances as we need
344
  instances = []
345
  try:
346
    try:
347
      num = qa_config.get("options", {}).get("burnin-instances", 1)
348
      for _ in range(0, num):
349
        instances.append(qa_config.AcquireInstance())
350
    except qa_error.OutOfInstancesError:
351
      print "Not enough instances, continuing anyway."
352

    
353
    if len(instances) < 1:
354
      raise qa_error.Error("Burnin needs at least one instance")
355

    
356
    script = qa_utils.UploadFile(master["primary"], "../tools/burnin")
357
    try:
358
      # Run burnin
359
      cmd = [script,
360
             "--os=%s" % qa_config.get("os"),
361
             "--disk-size=%s" % ",".join(qa_config.get("disk")),
362
             "--disk-growth=%s" % ",".join(qa_config.get("disk-growth")),
363
             "--disk-template=%s" % disk_template]
364
      if parallel:
365
        cmd.append("--parallel")
366
        cmd.append("--early-release")
367
      if check_inst:
368
        cmd.append("--http-check")
369
      if do_rename:
370
        cmd.append("--rename=%s" % do_rename)
371
      if not do_reboot:
372
        cmd.append("--no-reboot")
373
      else:
374
        cmd.append("--reboot-types=%s" % ",".join(reboot_types))
375
      cmd += [inst["name"] for inst in instances]
376
      AssertCommand(cmd)
377
    finally:
378
      AssertCommand(["rm", "-f", script])
379

    
380
  finally:
381
    for inst in instances:
382
      qa_config.ReleaseInstance(inst)
383

    
384

    
385
def TestClusterMasterFailover():
386
  """gnt-cluster master-failover"""
387
  master = qa_config.GetMasterNode()
388
  failovermaster = qa_config.AcquireNode(exclude=master)
389

    
390
  cmd = ["gnt-cluster", "master-failover"]
391
  try:
392
    AssertCommand(cmd, node=failovermaster)
393
    # Back to original master node
394
    AssertCommand(cmd, node=master)
395
  finally:
396
    qa_config.ReleaseNode(failovermaster)
397

    
398

    
399
def TestClusterMasterFailoverWithDrainedQueue():
400
  """gnt-cluster master-failover with drained queue"""
401
  drain_check = ["test", "-f", constants.JOB_QUEUE_DRAIN_FILE]
402

    
403
  master = qa_config.GetMasterNode()
404
  failovermaster = qa_config.AcquireNode(exclude=master)
405

    
406
  # Ensure queue is not drained
407
  for node in [master, failovermaster]:
408
    AssertCommand(drain_check, node=node, fail=True)
409

    
410
  # Drain queue on failover master
411
  AssertCommand(["touch", constants.JOB_QUEUE_DRAIN_FILE], node=failovermaster)
412

    
413
  cmd = ["gnt-cluster", "master-failover"]
414
  try:
415
    AssertCommand(drain_check, node=failovermaster)
416
    AssertCommand(cmd, node=failovermaster)
417
    AssertCommand(drain_check, fail=True)
418
    AssertCommand(drain_check, node=failovermaster, fail=True)
419

    
420
    # Back to original master node
421
    AssertCommand(cmd, node=master)
422
  finally:
423
    qa_config.ReleaseNode(failovermaster)
424

    
425
  AssertCommand(drain_check, fail=True)
426
  AssertCommand(drain_check, node=failovermaster, fail=True)
427

    
428

    
429
def TestClusterCopyfile():
430
  """gnt-cluster copyfile"""
431
  master = qa_config.GetMasterNode()
432

    
433
  uniqueid = utils.NewUUID()
434

    
435
  # Create temporary file
436
  f = tempfile.NamedTemporaryFile()
437
  f.write(uniqueid)
438
  f.flush()
439
  f.seek(0)
440

    
441
  # Upload file to master node
442
  testname = qa_utils.UploadFile(master["primary"], f.name)
443
  try:
444
    # Copy file to all nodes
445
    AssertCommand(["gnt-cluster", "copyfile", testname])
446
    _CheckFileOnAllNodes(testname, uniqueid)
447
  finally:
448
    _RemoveFileFromAllNodes(testname)
449

    
450

    
451
def TestClusterCommand():
452
  """gnt-cluster command"""
453
  uniqueid = utils.NewUUID()
454
  rfile = "/tmp/gnt%s" % utils.NewUUID()
455
  rcmd = utils.ShellQuoteArgs(["echo", "-n", uniqueid])
456
  cmd = utils.ShellQuoteArgs(["gnt-cluster", "command",
457
                              "%s >%s" % (rcmd, rfile)])
458

    
459
  try:
460
    AssertCommand(cmd)
461
    _CheckFileOnAllNodes(rfile, uniqueid)
462
  finally:
463
    _RemoveFileFromAllNodes(rfile)
464

    
465

    
466
def TestClusterDestroy():
467
  """gnt-cluster destroy"""
468
  AssertCommand(["gnt-cluster", "destroy", "--yes-do-it"])
469

    
470

    
471
def TestClusterRepairDiskSizes():
472
  """gnt-cluster repair-disk-sizes"""
473
  AssertCommand(["gnt-cluster", "repair-disk-sizes"])