Statistics
| Branch: | Tag: | Revision:

root / qa / qa_cluster.py @ a25f44a4

History | View | Annotate | Download (42.5 kB)

1
#
2
#
3

    
4
# Copyright (C) 2007, 2010, 2011, 2012, 2013 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 re
27
import tempfile
28
import os.path
29

    
30
from ganeti import constants
31
from ganeti import compat
32
from ganeti import utils
33
from ganeti import pathutils
34

    
35
import qa_config
36
import qa_daemon
37
import qa_utils
38
import qa_error
39
import qa_instance
40

    
41
from qa_utils import AssertEqual, AssertCommand, GetCommandOutput
42

    
43

    
44
# Prefix for LVM volumes created by QA code during tests
45
_QA_LV_PREFIX = "qa-"
46

    
47
#: cluster verify command
48
_CLUSTER_VERIFY = ["gnt-cluster", "verify"]
49

    
50

    
51
def _RemoveFileFromAllNodes(filename):
52
  """Removes a file from all nodes.
53

54
  """
55
  for node in qa_config.get("nodes"):
56
    AssertCommand(["rm", "-f", filename], node=node)
57

    
58

    
59
def _CheckFileOnAllNodes(filename, content):
60
  """Verifies the content of the given file on all nodes.
61

62
  """
63
  cmd = utils.ShellQuoteArgs(["cat", filename])
64
  for node in qa_config.get("nodes"):
65
    AssertEqual(qa_utils.GetCommandOutput(node.primary, cmd), content)
66

    
67

    
68
def _GetClusterField(field_path):
69
  """Get the value of a cluster field.
70

71
  @type field_path: list of strings
72
  @param field_path: Names of the groups/fields to navigate to get the desired
73
      value, e.g. C{["Default node parameters", "oob_program"]}
74
  @return: The effective value of the field (the actual type depends on the
75
      chosen field)
76

77
  """
78
  assert isinstance(field_path, list)
79
  assert field_path
80
  ret = qa_utils.GetObjectInfo(["gnt-cluster", "info"])
81
  for key in field_path:
82
    ret = ret[key]
83
  return ret
84

    
85

    
86
# Cluster-verify errors (date, "ERROR", then error code)
87
_CVERROR_RE = re.compile(r"^[\w\s:]+\s+- (ERROR|WARNING):([A-Z0-9_-]+):")
88

    
89

    
90
def _GetCVErrorCodes(cvout):
91
  errs = set()
92
  warns = set()
93
  for l in cvout.splitlines():
94
    m = _CVERROR_RE.match(l)
95
    if m:
96
      etype = m.group(1)
97
      ecode = m.group(2)
98
      if etype == "ERROR":
99
        errs.add(ecode)
100
      elif etype == "WARNING":
101
        warns.add(ecode)
102
  return (errs, warns)
103

    
104

    
105
def _CheckVerifyErrors(actual, expected, etype):
106
  exp_codes = compat.UniqueFrozenset(e for (_, e, _) in expected)
107
  if not actual.issuperset(exp_codes):
108
    missing = exp_codes.difference(actual)
109
    raise qa_error.Error("Cluster-verify didn't return these expected"
110
                         " %ss: %s" % (etype, utils.CommaJoin(missing)))
111

    
112

    
113
def AssertClusterVerify(fail=False, errors=None, warnings=None):
114
  """Run cluster-verify and check the result
115

116
  @type fail: bool
117
  @param fail: if cluster-verify is expected to fail instead of succeeding
118
  @type errors: list of tuples
119
  @param errors: List of CV_XXX errors that are expected; if specified, all the
120
      errors listed must appear in cluster-verify output. A non-empty value
121
      implies C{fail=True}.
122
  @type warnings: list of tuples
123
  @param warnings: Same as C{errors} but for warnings.
124

125
  """
126
  cvcmd = "gnt-cluster verify"
127
  mnode = qa_config.GetMasterNode()
128
  if errors or warnings:
129
    cvout = GetCommandOutput(mnode.primary, cvcmd + " --error-codes",
130
                             fail=(fail or errors))
131
    (act_errs, act_warns) = _GetCVErrorCodes(cvout)
132
    if errors:
133
      _CheckVerifyErrors(act_errs, errors, "error")
134
    if warnings:
135
      _CheckVerifyErrors(act_warns, warnings, "warning")
136
  else:
137
    AssertCommand(cvcmd, fail=fail, node=mnode)
138

    
139

    
140
# data for testing failures due to bad keys/values for disk parameters
141
_FAIL_PARAMS = ["nonexistent:resync-rate=1",
142
                "drbd:nonexistent=1",
143
                "drbd:resync-rate=invalid",
144
                ]
145

    
146

    
147
def TestClusterInitDisk():
148
  """gnt-cluster init -D"""
149
  name = qa_config.get("name")
150
  for param in _FAIL_PARAMS:
151
    AssertCommand(["gnt-cluster", "init", "-D", param, name], fail=True)
152

    
153

    
154
def TestClusterInit(rapi_user, rapi_secret):
155
  """gnt-cluster init"""
156
  master = qa_config.GetMasterNode()
157

    
158
  rapi_users_path = qa_utils.MakeNodePath(master, pathutils.RAPI_USERS_FILE)
159
  rapi_dir = os.path.dirname(rapi_users_path)
160

    
161
  # First create the RAPI credentials
162
  fh = tempfile.NamedTemporaryFile()
163
  try:
164
    fh.write("%s %s write\n" % (rapi_user, rapi_secret))
165
    fh.flush()
166

    
167
    tmpru = qa_utils.UploadFile(master.primary, fh.name)
168
    try:
169
      AssertCommand(["mkdir", "-p", rapi_dir])
170
      AssertCommand(["mv", tmpru, rapi_users_path])
171
    finally:
172
      AssertCommand(["rm", "-f", tmpru])
173
  finally:
174
    fh.close()
175

    
176
  # Initialize cluster
177
  enabled_disk_templates = qa_config.GetEnabledDiskTemplates()
178
  cmd = [
179
    "gnt-cluster", "init",
180
    "--primary-ip-version=%d" % qa_config.get("primary_ip_version", 4),
181
    "--enabled-hypervisors=%s" % ",".join(qa_config.GetEnabledHypervisors()),
182
    "--enabled-disk-templates=%s" %
183
      ",".join(enabled_disk_templates),
184
    ]
185
  if constants.DT_FILE in enabled_disk_templates:
186
    cmd.append(
187
        "--file-storage-dir=%s" %
188
        qa_config.get("default-file-storage-dir",
189
                      pathutils.DEFAULT_FILE_STORAGE_DIR))
190

    
191
  for spec_type in ("mem-size", "disk-size", "disk-count", "cpu-count",
192
                    "nic-count"):
193
    for spec_val in ("min", "max", "std"):
194
      spec = qa_config.get("ispec_%s_%s" %
195
                           (spec_type.replace("-", "_"), spec_val), None)
196
      if spec is not None:
197
        cmd.append("--specs-%s=%s=%d" % (spec_type, spec_val, spec))
198

    
199
  if master.secondary:
200
    cmd.append("--secondary-ip=%s" % master.secondary)
201

    
202
  if utils.IsLvmEnabled(qa_config.GetEnabledDiskTemplates()):
203
    vgname = qa_config.get("vg-name", constants.DEFAULT_VG)
204
    if vgname:
205
      cmd.append("--vg-name=%s" % vgname)
206
    else:
207
      raise qa_error.Error("Please specify a volume group if you enable"
208
                           " lvm-based disk templates in the QA.")
209

    
210
  master_netdev = qa_config.get("master-netdev", None)
211
  if master_netdev:
212
    cmd.append("--master-netdev=%s" % master_netdev)
213

    
214
  nicparams = qa_config.get("default-nicparams", None)
215
  if nicparams:
216
    cmd.append("--nic-parameters=%s" %
217
               ",".join(utils.FormatKeyValue(nicparams)))
218

    
219
  # Cluster value of the exclusive-storage node parameter
220
  e_s = qa_config.get("exclusive-storage")
221
  if e_s is not None:
222
    cmd.extend(["--node-parameters", "exclusive_storage=%s" % e_s])
223
  else:
224
    e_s = False
225
  qa_config.SetExclusiveStorage(e_s)
226

    
227
  extra_args = qa_config.get("cluster-init-args")
228
  if extra_args:
229
    cmd.extend(extra_args)
230

    
231
  cmd.append(qa_config.get("name"))
232

    
233
  AssertCommand(cmd)
234

    
235
  cmd = ["gnt-cluster", "modify"]
236

    
237
  # hypervisor parameter modifications
238
  hvp = qa_config.get("hypervisor-parameters", {})
239
  for k, v in hvp.items():
240
    cmd.extend(["-H", "%s:%s" % (k, v)])
241
  # backend parameter modifications
242
  bep = qa_config.get("backend-parameters", "")
243
  if bep:
244
    cmd.extend(["-B", bep])
245

    
246
  if len(cmd) > 2:
247
    AssertCommand(cmd)
248

    
249
  # OS parameters
250
  osp = qa_config.get("os-parameters", {})
251
  for k, v in osp.items():
252
    AssertCommand(["gnt-os", "modify", "-O", v, k])
253

    
254
  # OS hypervisor parameters
255
  os_hvp = qa_config.get("os-hvp", {})
256
  for os_name in os_hvp:
257
    for hv, hvp in os_hvp[os_name].items():
258
      AssertCommand(["gnt-os", "modify", "-H", "%s:%s" % (hv, hvp), os_name])
259

    
260

    
261
def TestClusterRename():
262
  """gnt-cluster rename"""
263
  cmd = ["gnt-cluster", "rename", "-f"]
264

    
265
  original_name = qa_config.get("name")
266
  rename_target = qa_config.get("rename", None)
267
  if rename_target is None:
268
    print qa_utils.FormatError('"rename" entry is missing')
269
    return
270

    
271
  for data in [
272
    cmd + [rename_target],
273
    _CLUSTER_VERIFY,
274
    cmd + [original_name],
275
    _CLUSTER_VERIFY,
276
    ]:
277
    AssertCommand(data)
278

    
279

    
280
def TestClusterOob():
281
  """out-of-band framework"""
282
  oob_path_exists = "/tmp/ganeti-qa-oob-does-exist-%s" % utils.NewUUID()
283

    
284
  AssertCommand(_CLUSTER_VERIFY)
285
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
286
                 "oob_program=/tmp/ganeti-qa-oob-does-not-exist-%s" %
287
                 utils.NewUUID()])
288

    
289
  AssertCommand(_CLUSTER_VERIFY, fail=True)
290

    
291
  AssertCommand(["touch", oob_path_exists])
292
  AssertCommand(["chmod", "0400", oob_path_exists])
293
  AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
294

    
295
  try:
296
    AssertCommand(["gnt-cluster", "modify", "--node-parameters",
297
                   "oob_program=%s" % oob_path_exists])
298

    
299
    AssertCommand(_CLUSTER_VERIFY, fail=True)
300

    
301
    AssertCommand(["chmod", "0500", oob_path_exists])
302
    AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
303

    
304
    AssertCommand(_CLUSTER_VERIFY)
305
  finally:
306
    AssertCommand(["gnt-cluster", "command", "rm", oob_path_exists])
307

    
308
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
309
                 "oob_program="])
310

    
311

    
312
def TestClusterEpo():
313
  """gnt-cluster epo"""
314
  master = qa_config.GetMasterNode()
315

    
316
  # Assert that OOB is unavailable for all nodes
317
  result_output = GetCommandOutput(master.primary,
318
                                   "gnt-node list --verbose --no-headers -o"
319
                                   " powered")
320
  AssertEqual(compat.all(powered == "(unavail)"
321
                         for powered in result_output.splitlines()), True)
322

    
323
  # Conflicting
324
  AssertCommand(["gnt-cluster", "epo", "--groups", "--all"], fail=True)
325
  # --all doesn't expect arguments
326
  AssertCommand(["gnt-cluster", "epo", "--all", "some_arg"], fail=True)
327

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

    
331
  # This shouldn't fail
332
  AssertCommand(["gnt-cluster", "epo", "-f", "--all"])
333

    
334
  # All instances should have been stopped now
335
  result_output = GetCommandOutput(master.primary,
336
                                   "gnt-instance list --no-headers -o status")
337
  # ERROR_down because the instance is stopped but not recorded as such
338
  AssertEqual(compat.all(status == "ERROR_down"
339
                         for status in result_output.splitlines()), True)
340

    
341
  # Now start everything again
342
  AssertCommand(["gnt-cluster", "epo", "--on", "-f", "--all"])
343

    
344
  # All instances should have been started now
345
  result_output = GetCommandOutput(master.primary,
346
                                   "gnt-instance list --no-headers -o status")
347
  AssertEqual(compat.all(status == "running"
348
                         for status in result_output.splitlines()), True)
349

    
350

    
351
def TestClusterVerify():
352
  """gnt-cluster verify"""
353
  AssertCommand(_CLUSTER_VERIFY)
354
  AssertCommand(["gnt-cluster", "verify-disks"])
355

    
356

    
357
def TestClusterVerifyDisksBrokenDRBD(instance, inst_nodes):
358
  """gnt-cluster verify-disks with broken DRBD"""
359
  qa_daemon.TestPauseWatcher()
360

    
361
  try:
362
    info = qa_instance.GetInstanceInfo(instance.name)
363
    snode = inst_nodes[1]
364
    for idx, minor in enumerate(info["drbd-minors"][snode.primary]):
365
      if idx % 2 == 0:
366
        break_drbd_cmd = \
367
          "(drbdsetup %d down >/dev/null 2>&1;" \
368
          " drbdsetup down resource%d >/dev/null 2>&1) || /bin/true" % \
369
          (minor, minor)
370
      else:
371
        break_drbd_cmd = \
372
          "(drbdsetup %d detach >/dev/null 2>&1;" \
373
          " drbdsetup detach %d >/dev/null 2>&1) || /bin/true" % \
374
          (minor, minor)
375
      AssertCommand(break_drbd_cmd, node=snode)
376

    
377
    verify_output = GetCommandOutput(qa_config.GetMasterNode().primary,
378
                                     "gnt-cluster verify-disks")
379
    activation_msg = "Activating disks for instance '%s'" % instance.name
380
    if activation_msg not in verify_output:
381
      raise qa_error.Error("gnt-cluster verify-disks did not activate broken"
382
                           " DRBD disks:\n%s" % verify_output)
383

    
384
    verify_output = GetCommandOutput(qa_config.GetMasterNode().primary,
385
                                     "gnt-cluster verify-disks")
386
    if activation_msg in verify_output:
387
      raise qa_error.Error("gnt-cluster verify-disks wants to activate broken"
388
                           " DRBD disks on second attempt:\n%s" % verify_output)
389

    
390
    AssertCommand(_CLUSTER_VERIFY)
391
  finally:
392
    qa_daemon.TestResumeWatcher()
393

    
394

    
395
def TestJobqueue():
396
  """gnt-debug test-jobqueue"""
397
  AssertCommand(["gnt-debug", "test-jobqueue"])
398

    
399

    
400
def TestDelay(node):
401
  """gnt-debug delay"""
402
  AssertCommand(["gnt-debug", "delay", "1"])
403
  AssertCommand(["gnt-debug", "delay", "--no-master", "1"])
404
  AssertCommand(["gnt-debug", "delay", "--no-master",
405
                 "-n", node.primary, "1"])
406

    
407

    
408
def TestClusterReservedLvs():
409
  """gnt-cluster reserved lvs"""
410
  # if no lvm-based templates are supported, skip the test
411
  if not qa_config.IsStorageTypeSupported(constants.ST_LVM_VG):
412
    return
413
  vgname = qa_config.get("vg-name", constants.DEFAULT_VG)
414
  lvname = _QA_LV_PREFIX + "test"
415
  lvfullname = "/".join([vgname, lvname])
416
  for fail, cmd in [
417
    (False, _CLUSTER_VERIFY),
418
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
419
    (False, ["lvcreate", "-L1G", "-n", lvname, vgname]),
420
    (True, _CLUSTER_VERIFY),
421
    (False, ["gnt-cluster", "modify", "--reserved-lvs",
422
             "%s,.*/other-test" % lvfullname]),
423
    (False, _CLUSTER_VERIFY),
424
    (False, ["gnt-cluster", "modify", "--reserved-lvs",
425
             ".*/%s.*" % _QA_LV_PREFIX]),
426
    (False, _CLUSTER_VERIFY),
427
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
428
    (True, _CLUSTER_VERIFY),
429
    (False, ["lvremove", "-f", lvfullname]),
430
    (False, _CLUSTER_VERIFY),
431
    ]:
432
    AssertCommand(cmd, fail=fail)
433

    
434

    
435
def TestClusterModifyEmpty():
436
  """gnt-cluster modify"""
437
  AssertCommand(["gnt-cluster", "modify"], fail=True)
438

    
439

    
440
def TestClusterModifyDisk():
441
  """gnt-cluster modify -D"""
442
  for param in _FAIL_PARAMS:
443
    AssertCommand(["gnt-cluster", "modify", "-D", param], fail=True)
444

    
445

    
446
def _GetOtherEnabledDiskTemplate(undesired_disk_templates,
447
                                 enabled_disk_templates):
448
  """Returns one template that is not in the undesired set.
449

450
  @type undesired_disk_templates: list of string
451
  @param undesired_disk_templates: a list of disk templates that we want to
452
      exclude when drawing one disk template from the list of enabled
453
      disk templates
454
  @type enabled_disk_templates: list of string
455
  @param enabled_disk_templates: list of enabled disk templates (in QA)
456

457
  """
458
  desired_templates = list(set(enabled_disk_templates)
459
                                - set(undesired_disk_templates))
460
  if desired_templates:
461
    template = desired_templates[0]
462
  else:
463
    # If no desired disk template is available for QA, choose 'diskless' and
464
    # hope for the best.
465
    template = constants.ST_DISKLESS
466

    
467
  return template
468

    
469

    
470
def TestClusterModifyFileBasedStorageDir(
471
    file_disk_template, dir_config_key, default_dir, option_name):
472
  """Tests gnt-cluster modify wrt to file-based directory options.
473

474
  @type file_disk_template: string
475
  @param file_disk_template: file-based disk template
476
  @type dir_config_key: string
477
  @param dir_config_key: key for the QA config to retrieve the default
478
     directory value
479
  @type default_dir: string
480
  @param default_dir: default directory, if the QA config does not specify
481
     it
482
  @type option_name: string
483
  @param option_name: name of the option of 'gnt-cluster modify' to
484
     change the directory
485

486
  """
487
  enabled_disk_templates = qa_config.GetEnabledDiskTemplates()
488
  assert file_disk_template in [constants.DT_FILE, constants.DT_SHARED_FILE]
489
  if not qa_config.IsTemplateSupported(file_disk_template):
490
    return
491

    
492
  # Get some non-file-based disk template to disable file storage
493
  other_disk_template = _GetOtherEnabledDiskTemplate(
494
      utils.storage.GetDiskTemplatesOfStorageType(constants.ST_FILE),
495
      enabled_disk_templates)
496

    
497
  file_storage_dir = qa_config.get(dir_config_key, default_dir)
498
  invalid_file_storage_dir = "/boot/"
499

    
500
  for fail, cmd in [
501
    (False, ["gnt-cluster", "modify",
502
            "--enabled-disk-templates=%s" % file_disk_template]),
503
    (False, ["gnt-cluster", "modify",
504
            "--%s=%s" % (option_name, file_storage_dir)]),
505
    (False, ["gnt-cluster", "modify",
506
            "--%s=%s" % (option_name, invalid_file_storage_dir)]),
507
    # file storage dir is set to an inacceptable path, thus verify
508
    # should fail
509
    (True, ["gnt-cluster", "verify"]),
510
    # unsetting the storage dir while file storage is enabled
511
    # should fail
512
    (True, ["gnt-cluster", "modify",
513
            "--%s=" % option_name]),
514
    (False, ["gnt-cluster", "modify",
515
            "--%s=%s" % (option_name, file_storage_dir)]),
516
    (False, ["gnt-cluster", "modify",
517
            "--enabled-disk-templates=%s" % other_disk_template]),
518
    (False, ["gnt-cluster", "modify",
519
            "--%s=%s" % (option_name, invalid_file_storage_dir)]),
520
    # file storage is set to an inacceptable path, but file storage
521
    # is disabled, thus verify should not fail
522
    (False, ["gnt-cluster", "verify"]),
523
    # unsetting the file storage dir while file storage is not enabled
524
    # should be fine
525
    (False, ["gnt-cluster", "modify",
526
            "--%s=" % option_name]),
527
    # resetting everything to sane values
528
    (False, ["gnt-cluster", "modify",
529
            "--%s=%s" % (option_name, file_storage_dir),
530
            "--enabled-disk-templates=%s" % ",".join(enabled_disk_templates)])
531
    ]:
532
    AssertCommand(cmd, fail=fail)
533

    
534

    
535
def TestClusterModifyFileStorageDir():
536
  """gnt-cluster modify --file-storage-dir=..."""
537
  TestClusterModifyFileBasedStorageDir(
538
      constants.DT_FILE, "default-file-storage-dir",
539
      pathutils.DEFAULT_FILE_STORAGE_DIR,
540
      "file-storage-dir")
541

    
542

    
543
def TestClusterModifySharedFileStorageDir():
544
  """gnt-cluster modify --shared-file-storage-dir=..."""
545
  TestClusterModifyFileBasedStorageDir(
546
      constants.DT_SHARED_FILE, "default-shared-file-storage-dir",
547
      pathutils.DEFAULT_SHARED_FILE_STORAGE_DIR,
548
      "shared-file-storage-dir")
549

    
550

    
551
def TestClusterModifyDiskTemplates():
552
  """gnt-cluster modify --enabled-disk-templates=..."""
553
  enabled_disk_templates = qa_config.GetEnabledDiskTemplates()
554
  default_disk_template = qa_config.GetDefaultDiskTemplate()
555

    
556
  _TestClusterModifyDiskTemplatesArguments(default_disk_template)
557
  _TestClusterModifyDiskTemplatesDrbdHelper(enabled_disk_templates)
558
  _TestClusterModifyDiskTemplatesVgName(enabled_disk_templates)
559

    
560
  _RestoreEnabledDiskTemplates()
561
  nodes = qa_config.AcquireManyNodes(2)
562

    
563
  instance_template = enabled_disk_templates[0]
564
  instance = qa_instance.CreateInstanceByDiskTemplate(nodes, instance_template)
565

    
566
  _TestClusterModifyUnusedDiskTemplate(instance_template)
567
  _TestClusterModifyUsedDiskTemplate(instance_template,
568
                                     enabled_disk_templates)
569

    
570
  qa_instance.TestInstanceRemove(instance)
571
  _RestoreEnabledDiskTemplates()
572

    
573

    
574
def _RestoreEnabledDiskTemplates():
575
  """Sets the list of enabled disk templates back to the list of enabled disk
576
     templates from the QA configuration. This can be used to make sure that
577
     the tests that modify the list of disk templates do not interfere with
578
     other tests.
579

580
  """
581
  enabled_disk_templates = qa_config.GetEnabledDiskTemplates()
582
  cmd = ["gnt-cluster", "modify",
583
         "--enabled-disk-templates=%s" % ",".join(enabled_disk_templates),
584
         "--ipolicy-disk-templates=%s" % ",".join(enabled_disk_templates),
585
         ]
586

    
587
  if utils.IsLvmEnabled(qa_config.GetEnabledDiskTemplates()):
588
    vgname = qa_config.get("vg-name", constants.DEFAULT_VG)
589
    cmd.append("--vg-name=%s" % vgname)
590

    
591
  AssertCommand(cmd, fail=False)
592

    
593

    
594
def _TestClusterModifyDiskTemplatesDrbdHelper(enabled_disk_templates):
595
  """Tests argument handling of 'gnt-cluster modify' with respect to
596
     the parameter '--drbd-usermode-helper'. This test is independent
597
     of instances.
598

599
  """
600
  _RestoreEnabledDiskTemplates()
601

    
602
  if constants.DT_DRBD8 not in enabled_disk_templates:
603
    return
604
  if constants.DT_PLAIN not in enabled_disk_templates:
605
    return
606

    
607
  drbd_usermode_helper = qa_config.get("drbd-usermode-helper", "/bin/true")
608
  bogus_usermode_helper = "/tmp/pinkbunny"
609
  for command, fail in \
610
      [(["gnt-cluster", "modify",
611
         "--enabled-disk-templates=%s" % constants.DT_DRBD8,
612
         "--ipolicy-disk-templates=%s" % constants.DT_DRBD8], False),
613
       (["gnt-cluster", "modify",
614
         "--drbd-usermode-helper=%s" % drbd_usermode_helper], False),
615
       (["gnt-cluster", "modify",
616
         "--drbd-usermode-helper=%s" % bogus_usermode_helper], True),
617
       # unsetting helper when DRBD is enabled should not work
618
       (["gnt-cluster", "modify",
619
         "--drbd-usermode-helper="], True),
620
       (["gnt-cluster", "modify",
621
         "--enabled-disk-templates=%s" % constants.DT_PLAIN,
622
         "--ipolicy-disk-templates=%s" % constants.DT_PLAIN], False),
623
       (["gnt-cluster", "modify",
624
         "--drbd-usermode-helper="], True),
625
       (["gnt-cluster", "modify",
626
         "--drbd-usermode-helper=%s" % drbd_usermode_helper], False),
627
       (["gnt-cluster", "modify",
628
         "--drbd-usermode-helper=%s" % drbd_usermode_helper,
629
         "--enabled-disk-templates=%s" % constants.DT_DRBD8,
630
         "--ipolicy-disk-templates=%s" % constants.DT_DRBD8], False),
631
       (["gnt-cluster", "modify",
632
         "--drbd-usermode-helper=",
633
         "--enabled-disk-templates=%s" % constants.DT_PLAIN,
634
         "--ipolicy-disk-templates=%s" % constants.DT_PLAIN], False),
635
       (["gnt-cluster", "modify",
636
         "--drbd-usermode-helper=%s" % drbd_usermode_helper,
637
         "--enabled-disk-templates=%s" % constants.DT_DRBD8,
638
         "--ipolicy-disk-templates=%s" % constants.DT_DRBD8], False),
639
      ]:
640
    AssertCommand(command, fail=fail)
641
  _RestoreEnabledDiskTemplates()
642

    
643

    
644
def _TestClusterModifyDiskTemplatesArguments(default_disk_template):
645
  """Tests argument handling of 'gnt-cluster modify' with respect to
646
     the parameter '--enabled-disk-templates'. This test is independent
647
     of instances.
648

649
  """
650
  _RestoreEnabledDiskTemplates()
651

    
652
  # bogus templates
653
  AssertCommand(["gnt-cluster", "modify",
654
                 "--enabled-disk-templates=pinkbunny"],
655
                fail=True)
656

    
657
  # duplicate entries do no harm
658
  AssertCommand(
659
    ["gnt-cluster", "modify",
660
     "--enabled-disk-templates=%s,%s" %
661
      (default_disk_template, default_disk_template),
662
     "--ipolicy-disk-templates=%s" % default_disk_template],
663
    fail=False)
664

    
665

    
666
def _TestClusterModifyDiskTemplatesVgName(enabled_disk_templates):
667
  """Tests argument handling of 'gnt-cluster modify' with respect to
668
     the parameter '--enabled-disk-templates' and '--vg-name'. This test is
669
     independent of instances.
670

671
  """
672
  if not utils.IsLvmEnabled(enabled_disk_templates):
673
    # These tests only make sense if lvm is enabled for QA
674
    return
675

    
676
  # determine an LVM and a non-LVM disk template for the tests
677
  non_lvm_template = _GetOtherEnabledDiskTemplate(utils.GetLvmDiskTemplates(),
678
                                                  enabled_disk_templates)
679
  lvm_template = list(set(enabled_disk_templates)
680
                      .intersection(set(utils.GetLvmDiskTemplates())))[0]
681

    
682
  vgname = qa_config.get("vg-name", constants.DEFAULT_VG)
683

    
684
  # Clean start: unset volume group name, disable lvm storage
685
  AssertCommand(
686
    ["gnt-cluster", "modify",
687
     "--enabled-disk-templates=%s" % non_lvm_template,
688
     "--ipolicy-disk-templates=%s" % non_lvm_template,
689
     "--vg-name="],
690
    fail=False)
691

    
692
  # Try to enable lvm, when no volume group is given
693
  AssertCommand(
694
    ["gnt-cluster", "modify",
695
     "--enabled-disk-templates=%s" % lvm_template,
696
     "--ipolicy-disk-templates=%s" % lvm_template],
697
    fail=True)
698

    
699
  # Set volume group, with lvm still disabled: just a warning
700
  AssertCommand(["gnt-cluster", "modify", "--vg-name=%s" % vgname], fail=False)
701

    
702
  # Try unsetting vg name and enabling lvm at the same time
703
  AssertCommand(
704
    ["gnt-cluster", "modify",
705
     "--enabled-disk-templates=%s" % lvm_template,
706
     "--ipolicy-disk-templates=%s" % lvm_template,
707
     "--vg-name="],
708
    fail=True)
709

    
710
  # Enable lvm with vg name present
711
  AssertCommand(
712
    ["gnt-cluster", "modify",
713
     "--enabled-disk-templates=%s" % lvm_template,
714
     "--ipolicy-disk-templates=%s" % lvm_template],
715
    fail=False)
716

    
717
  # Try unsetting vg name with lvm still enabled
718
  AssertCommand(["gnt-cluster", "modify", "--vg-name="], fail=True)
719

    
720
  # Disable lvm with vg name still set
721
  AssertCommand(
722
    ["gnt-cluster", "modify",
723
     "--enabled-disk-templates=%s" % non_lvm_template,
724
     "--ipolicy-disk-templates=%s" % non_lvm_template,
725
     ],
726
    fail=False)
727

    
728
  # Try unsetting vg name with lvm disabled
729
  AssertCommand(["gnt-cluster", "modify", "--vg-name="], fail=False)
730

    
731
  # Set vg name and enable lvm at the same time
732
  AssertCommand(
733
    ["gnt-cluster", "modify",
734
     "--enabled-disk-templates=%s" % lvm_template,
735
     "--ipolicy-disk-templates=%s" % lvm_template,
736
     "--vg-name=%s" % vgname],
737
    fail=False)
738

    
739
  # Unset vg name and disable lvm at the same time
740
  AssertCommand(
741
    ["gnt-cluster", "modify",
742
     "--enabled-disk-templates=%s" % non_lvm_template,
743
     "--ipolicy-disk-templates=%s" % non_lvm_template,
744
     "--vg-name="],
745
    fail=False)
746

    
747
  _RestoreEnabledDiskTemplates()
748

    
749

    
750
def _TestClusterModifyUsedDiskTemplate(instance_template,
751
                                       enabled_disk_templates):
752
  """Tests that disk templates that are currently in use by instances cannot
753
     be disabled on the cluster.
754

755
  """
756
  # If the list of enabled disk templates contains only one template
757
  # we need to add some other templates, because the list of enabled disk
758
  # templates can only be set to a non-empty list.
759
  new_disk_templates = list(set(enabled_disk_templates)
760
                              - set([instance_template]))
761
  if not new_disk_templates:
762
    new_disk_templates = list(set([constants.DT_DISKLESS, constants.DT_BLOCK])
763
                                - set([instance_template]))
764
  AssertCommand(
765
    ["gnt-cluster", "modify",
766
     "--enabled-disk-templates=%s" % ",".join(new_disk_templates),
767
     "--ipolicy-disk-templates=%s" % ",".join(new_disk_templates)],
768
    fail=True)
769

    
770

    
771
def _TestClusterModifyUnusedDiskTemplate(instance_template):
772
  """Tests that unused disk templates can be disabled safely."""
773
  all_disk_templates = constants.DISK_TEMPLATES
774
  if not utils.IsLvmEnabled(qa_config.GetEnabledDiskTemplates()):
775
    all_disk_templates = list(set(all_disk_templates) -
776
                              set(utils.GetLvmDiskTemplates()))
777

    
778
  AssertCommand(
779
    ["gnt-cluster", "modify",
780
     "--enabled-disk-templates=%s" % ",".join(all_disk_templates),
781
     "--ipolicy-disk-templates=%s" % ",".join(all_disk_templates)],
782
    fail=False)
783
  new_disk_templates = [instance_template]
784
  AssertCommand(
785
    ["gnt-cluster", "modify",
786
     "--enabled-disk-templates=%s" % ",".join(new_disk_templates),
787
     "--ipolicy-disk-templates=%s" % ",".join(new_disk_templates)],
788
    fail=False)
789

    
790

    
791
def TestClusterModifyBe():
792
  """gnt-cluster modify -B"""
793
  for fail, cmd in [
794
    # max/min mem
795
    (False, ["gnt-cluster", "modify", "-B", "maxmem=256"]),
796
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *maxmem: 256$'"]),
797
    (False, ["gnt-cluster", "modify", "-B", "minmem=256"]),
798
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *minmem: 256$'"]),
799
    (True, ["gnt-cluster", "modify", "-B", "maxmem=a"]),
800
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *maxmem: 256$'"]),
801
    (True, ["gnt-cluster", "modify", "-B", "minmem=a"]),
802
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *minmem: 256$'"]),
803
    (False, ["gnt-cluster", "modify", "-B", "maxmem=128,minmem=128"]),
804
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *maxmem: 128$'"]),
805
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *minmem: 128$'"]),
806
    # vcpus
807
    (False, ["gnt-cluster", "modify", "-B", "vcpus=4"]),
808
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 4$'"]),
809
    (True, ["gnt-cluster", "modify", "-B", "vcpus=a"]),
810
    (False, ["gnt-cluster", "modify", "-B", "vcpus=1"]),
811
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 1$'"]),
812
    # auto_balance
813
    (False, ["gnt-cluster", "modify", "-B", "auto_balance=False"]),
814
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: False$'"]),
815
    (True, ["gnt-cluster", "modify", "-B", "auto_balance=1"]),
816
    (False, ["gnt-cluster", "modify", "-B", "auto_balance=True"]),
817
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: True$'"]),
818
    ]:
819
    AssertCommand(cmd, fail=fail)
820

    
821
  # redo the original-requested BE parameters, if any
822
  bep = qa_config.get("backend-parameters", "")
823
  if bep:
824
    AssertCommand(["gnt-cluster", "modify", "-B", bep])
825

    
826

    
827
def _GetClusterIPolicy():
828
  """Return the run-time values of the cluster-level instance policy.
829

830
  @rtype: tuple
831
  @return: (policy, specs), where:
832
      - policy is a dictionary of the policy values, instance specs excluded
833
      - specs is a dictionary containing only the specs, using the internal
834
        format (see L{constants.IPOLICY_DEFAULTS} for an example)
835

836
  """
837
  info = qa_utils.GetObjectInfo(["gnt-cluster", "info"])
838
  policy = info["Instance policy - limits for instances"]
839
  (ret_policy, ret_specs) = qa_utils.ParseIPolicy(policy)
840

    
841
  # Sanity checks
842
  assert "minmax" in ret_specs and "std" in ret_specs
843
  assert len(ret_specs["minmax"]) > 0
844
  assert len(ret_policy) > 0
845
  return (ret_policy, ret_specs)
846

    
847

    
848
def TestClusterModifyIPolicy():
849
  """gnt-cluster modify --ipolicy-*"""
850
  basecmd = ["gnt-cluster", "modify"]
851
  (old_policy, old_specs) = _GetClusterIPolicy()
852
  for par in ["vcpu-ratio", "spindle-ratio"]:
853
    curr_val = float(old_policy[par])
854
    test_values = [
855
      (True, 1.0),
856
      (True, 1.5),
857
      (True, 2),
858
      (False, "a"),
859
      # Restore the old value
860
      (True, curr_val),
861
      ]
862
    for (good, val) in test_values:
863
      cmd = basecmd + ["--ipolicy-%s=%s" % (par, val)]
864
      AssertCommand(cmd, fail=not good)
865
      if good:
866
        curr_val = val
867
      # Check the affected parameter
868
      (eff_policy, eff_specs) = _GetClusterIPolicy()
869
      AssertEqual(float(eff_policy[par]), curr_val)
870
      # Check everything else
871
      AssertEqual(eff_specs, old_specs)
872
      for p in eff_policy.keys():
873
        if p == par:
874
          continue
875
        AssertEqual(eff_policy[p], old_policy[p])
876

    
877
  # Allowing disk templates via ipolicy requires them to be
878
  # enabled on the cluster.
879
  if not (qa_config.IsTemplateSupported(constants.DT_PLAIN)
880
          and qa_config.IsTemplateSupported(constants.DT_DRBD8)):
881
    return
882
  # Disk templates are treated slightly differently
883
  par = "disk-templates"
884
  disp_str = "allowed disk templates"
885
  curr_val = old_policy[disp_str]
886
  test_values = [
887
    (True, constants.DT_PLAIN),
888
    (True, "%s,%s" % (constants.DT_PLAIN, constants.DT_DRBD8)),
889
    (False, "thisisnotadisktemplate"),
890
    (False, ""),
891
    # Restore the old value
892
    (True, curr_val.replace(" ", "")),
893
    ]
894
  for (good, val) in test_values:
895
    cmd = basecmd + ["--ipolicy-%s=%s" % (par, val)]
896
    AssertCommand(cmd, fail=not good)
897
    if good:
898
      curr_val = val
899
    # Check the affected parameter
900
    (eff_policy, eff_specs) = _GetClusterIPolicy()
901
    AssertEqual(eff_policy[disp_str].replace(" ", ""), curr_val)
902
    # Check everything else
903
    AssertEqual(eff_specs, old_specs)
904
    for p in eff_policy.keys():
905
      if p == disp_str:
906
        continue
907
      AssertEqual(eff_policy[p], old_policy[p])
908

    
909

    
910
def TestClusterSetISpecs(new_specs=None, diff_specs=None, fail=False,
911
                         old_values=None):
912
  """Change instance specs.
913

914
  At most one of new_specs or diff_specs can be specified.
915

916
  @type new_specs: dict
917
  @param new_specs: new complete specs, in the same format returned by
918
      L{_GetClusterIPolicy}
919
  @type diff_specs: dict
920
  @param diff_specs: partial specs, it can be an incomplete specifications, but
921
      if min/max specs are specified, their number must match the number of the
922
      existing specs
923
  @type fail: bool
924
  @param fail: if the change is expected to fail
925
  @type old_values: tuple
926
  @param old_values: (old_policy, old_specs), as returned by
927
      L{_GetClusterIPolicy}
928
  @return: same as L{_GetClusterIPolicy}
929

930
  """
931
  build_cmd = lambda opts: ["gnt-cluster", "modify"] + opts
932
  return qa_utils.TestSetISpecs(
933
    new_specs=new_specs, diff_specs=diff_specs,
934
    get_policy_fn=_GetClusterIPolicy, build_cmd_fn=build_cmd,
935
    fail=fail, old_values=old_values)
936

    
937

    
938
def TestClusterModifyISpecs():
939
  """gnt-cluster modify --specs-*"""
940
  params = ["memory-size", "disk-size", "disk-count", "cpu-count", "nic-count"]
941
  (cur_policy, cur_specs) = _GetClusterIPolicy()
942
  # This test assumes that there is only one min/max bound
943
  assert len(cur_specs[constants.ISPECS_MINMAX]) == 1
944
  for par in params:
945
    test_values = [
946
      (True, 0, 4, 12),
947
      (True, 4, 4, 12),
948
      (True, 4, 12, 12),
949
      (True, 4, 4, 4),
950
      (False, 4, 0, 12),
951
      (False, 4, 16, 12),
952
      (False, 4, 4, 0),
953
      (False, 12, 4, 4),
954
      (False, 12, 4, 0),
955
      (False, "a", 4, 12),
956
      (False, 0, "a", 12),
957
      (False, 0, 4, "a"),
958
      # This is to restore the old values
959
      (True,
960
       cur_specs[constants.ISPECS_MINMAX][0][constants.ISPECS_MIN][par],
961
       cur_specs[constants.ISPECS_STD][par],
962
       cur_specs[constants.ISPECS_MINMAX][0][constants.ISPECS_MAX][par])
963
      ]
964
    for (good, mn, st, mx) in test_values:
965
      new_vals = {
966
        constants.ISPECS_MINMAX: [{
967
          constants.ISPECS_MIN: {par: mn},
968
          constants.ISPECS_MAX: {par: mx}
969
          }],
970
        constants.ISPECS_STD: {par: st}
971
        }
972
      cur_state = (cur_policy, cur_specs)
973
      # We update cur_specs, as we've copied the values to restore already
974
      (cur_policy, cur_specs) = TestClusterSetISpecs(
975
        diff_specs=new_vals, fail=not good, old_values=cur_state)
976

    
977
    # Get the ipolicy command
978
    mnode = qa_config.GetMasterNode()
979
    initcmd = GetCommandOutput(mnode.primary, "gnt-cluster show-ispecs-cmd")
980
    modcmd = ["gnt-cluster", "modify"]
981
    opts = initcmd.split()
982
    assert opts[0:2] == ["gnt-cluster", "init"]
983
    for k in range(2, len(opts) - 1):
984
      if opts[k].startswith("--ipolicy-"):
985
        assert k + 2 <= len(opts)
986
        modcmd.extend(opts[k:k + 2])
987
    # Re-apply the ipolicy (this should be a no-op)
988
    AssertCommand(modcmd)
989
    new_initcmd = GetCommandOutput(mnode.primary, "gnt-cluster show-ispecs-cmd")
990
    AssertEqual(initcmd, new_initcmd)
991

    
992

    
993
def TestClusterInfo():
994
  """gnt-cluster info"""
995
  AssertCommand(["gnt-cluster", "info"])
996

    
997

    
998
def TestClusterRedistConf():
999
  """gnt-cluster redist-conf"""
1000
  AssertCommand(["gnt-cluster", "redist-conf"])
1001

    
1002

    
1003
def TestClusterGetmaster():
1004
  """gnt-cluster getmaster"""
1005
  AssertCommand(["gnt-cluster", "getmaster"])
1006

    
1007

    
1008
def TestClusterVersion():
1009
  """gnt-cluster version"""
1010
  AssertCommand(["gnt-cluster", "version"])
1011

    
1012

    
1013
def TestClusterRenewCrypto():
1014
  """gnt-cluster renew-crypto"""
1015
  master = qa_config.GetMasterNode()
1016

    
1017
  # Conflicting options
1018
  cmd = ["gnt-cluster", "renew-crypto", "--force",
1019
         "--new-cluster-certificate", "--new-confd-hmac-key"]
1020
  conflicting = [
1021
    ["--new-rapi-certificate", "--rapi-certificate=/dev/null"],
1022
    ["--new-cluster-domain-secret", "--cluster-domain-secret=/dev/null"],
1023
    ]
1024
  for i in conflicting:
1025
    AssertCommand(cmd + i, fail=True)
1026

    
1027
  # Invalid RAPI certificate
1028
  cmd = ["gnt-cluster", "renew-crypto", "--force",
1029
         "--rapi-certificate=/dev/null"]
1030
  AssertCommand(cmd, fail=True)
1031

    
1032
  rapi_cert_backup = qa_utils.BackupFile(master.primary,
1033
                                         pathutils.RAPI_CERT_FILE)
1034
  try:
1035
    # Custom RAPI certificate
1036
    fh = tempfile.NamedTemporaryFile()
1037

    
1038
    # Ensure certificate doesn't cause "gnt-cluster verify" to complain
1039
    validity = constants.SSL_CERT_EXPIRATION_WARN * 3
1040

    
1041
    utils.GenerateSelfSignedSslCert(fh.name, validity=validity)
1042

    
1043
    tmpcert = qa_utils.UploadFile(master.primary, fh.name)
1044
    try:
1045
      AssertCommand(["gnt-cluster", "renew-crypto", "--force",
1046
                     "--rapi-certificate=%s" % tmpcert])
1047
    finally:
1048
      AssertCommand(["rm", "-f", tmpcert])
1049

    
1050
    # Custom cluster domain secret
1051
    cds_fh = tempfile.NamedTemporaryFile()
1052
    cds_fh.write(utils.GenerateSecret())
1053
    cds_fh.write("\n")
1054
    cds_fh.flush()
1055

    
1056
    tmpcds = qa_utils.UploadFile(master.primary, cds_fh.name)
1057
    try:
1058
      AssertCommand(["gnt-cluster", "renew-crypto", "--force",
1059
                     "--cluster-domain-secret=%s" % tmpcds])
1060
    finally:
1061
      AssertCommand(["rm", "-f", tmpcds])
1062

    
1063
    # Normal case
1064
    AssertCommand(["gnt-cluster", "renew-crypto", "--force",
1065
                   "--new-cluster-certificate", "--new-confd-hmac-key",
1066
                   "--new-rapi-certificate", "--new-cluster-domain-secret"])
1067

    
1068
    # Restore RAPI certificate
1069
    AssertCommand(["gnt-cluster", "renew-crypto", "--force",
1070
                   "--rapi-certificate=%s" % rapi_cert_backup])
1071
  finally:
1072
    AssertCommand(["rm", "-f", rapi_cert_backup])
1073

    
1074

    
1075
def TestClusterBurnin():
1076
  """Burnin"""
1077
  master = qa_config.GetMasterNode()
1078

    
1079
  options = qa_config.get("options", {})
1080
  disk_template = options.get("burnin-disk-template", constants.DT_DRBD8)
1081
  parallel = options.get("burnin-in-parallel", False)
1082
  check_inst = options.get("burnin-check-instances", False)
1083
  do_rename = options.get("burnin-rename", "")
1084
  do_reboot = options.get("burnin-reboot", True)
1085
  reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
1086

    
1087
  # Get as many instances as we need
1088
  instances = []
1089
  try:
1090
    try:
1091
      num = qa_config.get("options", {}).get("burnin-instances", 1)
1092
      for _ in range(0, num):
1093
        instances.append(qa_config.AcquireInstance())
1094
    except qa_error.OutOfInstancesError:
1095
      print "Not enough instances, continuing anyway."
1096

    
1097
    if len(instances) < 1:
1098
      raise qa_error.Error("Burnin needs at least one instance")
1099

    
1100
    script = qa_utils.UploadFile(master.primary, "../tools/burnin")
1101
    try:
1102
      disks = qa_config.GetDiskOptions()
1103
      # Run burnin
1104
      cmd = [script,
1105
             "--os=%s" % qa_config.get("os"),
1106
             "--minmem-size=%s" % qa_config.get(constants.BE_MINMEM),
1107
             "--maxmem-size=%s" % qa_config.get(constants.BE_MAXMEM),
1108
             "--disk-size=%s" % ",".join([d.get("size") for d in disks]),
1109
             "--disk-growth=%s" % ",".join([d.get("growth") for d in disks]),
1110
             "--disk-template=%s" % disk_template]
1111
      if parallel:
1112
        cmd.append("--parallel")
1113
        cmd.append("--early-release")
1114
      if check_inst:
1115
        cmd.append("--http-check")
1116
      if do_rename:
1117
        cmd.append("--rename=%s" % do_rename)
1118
      if not do_reboot:
1119
        cmd.append("--no-reboot")
1120
      else:
1121
        cmd.append("--reboot-types=%s" % ",".join(reboot_types))
1122
      cmd += [inst.name for inst in instances]
1123
      AssertCommand(cmd)
1124
    finally:
1125
      AssertCommand(["rm", "-f", script])
1126

    
1127
  finally:
1128
    for inst in instances:
1129
      inst.Release()
1130

    
1131

    
1132
def TestClusterMasterFailover():
1133
  """gnt-cluster master-failover"""
1134
  master = qa_config.GetMasterNode()
1135
  failovermaster = qa_config.AcquireNode(exclude=master)
1136

    
1137
  cmd = ["gnt-cluster", "master-failover"]
1138
  try:
1139
    AssertCommand(cmd, node=failovermaster)
1140
    # Back to original master node
1141
    AssertCommand(cmd, node=master)
1142
  finally:
1143
    failovermaster.Release()
1144

    
1145

    
1146
def _NodeQueueDrainFile(node):
1147
  """Returns path to queue drain file for a node.
1148

1149
  """
1150
  return qa_utils.MakeNodePath(node, pathutils.JOB_QUEUE_DRAIN_FILE)
1151

    
1152

    
1153
def _AssertDrainFile(node, **kwargs):
1154
  """Checks for the queue drain file.
1155

1156
  """
1157
  AssertCommand(["test", "-f", _NodeQueueDrainFile(node)], node=node, **kwargs)
1158

    
1159

    
1160
def TestClusterMasterFailoverWithDrainedQueue():
1161
  """gnt-cluster master-failover with drained queue"""
1162
  master = qa_config.GetMasterNode()
1163
  failovermaster = qa_config.AcquireNode(exclude=master)
1164

    
1165
  # Ensure queue is not drained
1166
  for node in [master, failovermaster]:
1167
    _AssertDrainFile(node, fail=True)
1168

    
1169
  # Drain queue on failover master
1170
  AssertCommand(["touch", _NodeQueueDrainFile(failovermaster)],
1171
                node=failovermaster)
1172

    
1173
  cmd = ["gnt-cluster", "master-failover"]
1174
  try:
1175
    _AssertDrainFile(failovermaster)
1176
    AssertCommand(cmd, node=failovermaster)
1177
    _AssertDrainFile(master, fail=True)
1178
    _AssertDrainFile(failovermaster, fail=True)
1179

    
1180
    # Back to original master node
1181
    AssertCommand(cmd, node=master)
1182
  finally:
1183
    failovermaster.Release()
1184

    
1185
  # Ensure queue is not drained
1186
  for node in [master, failovermaster]:
1187
    _AssertDrainFile(node, fail=True)
1188

    
1189

    
1190
def TestClusterCopyfile():
1191
  """gnt-cluster copyfile"""
1192
  master = qa_config.GetMasterNode()
1193

    
1194
  uniqueid = utils.NewUUID()
1195

    
1196
  # Create temporary file
1197
  f = tempfile.NamedTemporaryFile()
1198
  f.write(uniqueid)
1199
  f.flush()
1200
  f.seek(0)
1201

    
1202
  # Upload file to master node
1203
  testname = qa_utils.UploadFile(master.primary, f.name)
1204
  try:
1205
    # Copy file to all nodes
1206
    AssertCommand(["gnt-cluster", "copyfile", testname])
1207
    _CheckFileOnAllNodes(testname, uniqueid)
1208
  finally:
1209
    _RemoveFileFromAllNodes(testname)
1210

    
1211

    
1212
def TestClusterCommand():
1213
  """gnt-cluster command"""
1214
  uniqueid = utils.NewUUID()
1215
  rfile = "/tmp/gnt%s" % utils.NewUUID()
1216
  rcmd = utils.ShellQuoteArgs(["echo", "-n", uniqueid])
1217
  cmd = utils.ShellQuoteArgs(["gnt-cluster", "command",
1218
                              "%s >%s" % (rcmd, rfile)])
1219

    
1220
  try:
1221
    AssertCommand(cmd)
1222
    _CheckFileOnAllNodes(rfile, uniqueid)
1223
  finally:
1224
    _RemoveFileFromAllNodes(rfile)
1225

    
1226

    
1227
def TestClusterDestroy():
1228
  """gnt-cluster destroy"""
1229
  AssertCommand(["gnt-cluster", "destroy", "--yes-do-it"])
1230

    
1231

    
1232
def TestClusterRepairDiskSizes():
1233
  """gnt-cluster repair-disk-sizes"""
1234
  AssertCommand(["gnt-cluster", "repair-disk-sizes"])
1235

    
1236

    
1237
def TestSetExclStorCluster(newvalue):
1238
  """Set the exclusive_storage node parameter at the cluster level.
1239

1240
  @type newvalue: bool
1241
  @param newvalue: New value of exclusive_storage
1242
  @rtype: bool
1243
  @return: The old value of exclusive_storage
1244

1245
  """
1246
  es_path = ["Default node parameters", "exclusive_storage"]
1247
  oldvalue = _GetClusterField(es_path)
1248
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
1249
                 "exclusive_storage=%s" % newvalue])
1250
  effvalue = _GetClusterField(es_path)
1251
  if effvalue != newvalue:
1252
    raise qa_error.Error("exclusive_storage has the wrong value: %s instead"
1253
                         " of %s" % (effvalue, newvalue))
1254
  qa_config.SetExclusiveStorage(newvalue)
1255
  return oldvalue
1256

    
1257

    
1258
def TestExclStorSharedPv(node):
1259
  """cluster-verify reports LVs that share the same PV with exclusive_storage.
1260

1261
  """
1262
  vgname = qa_config.get("vg-name", constants.DEFAULT_VG)
1263
  lvname1 = _QA_LV_PREFIX + "vol1"
1264
  lvname2 = _QA_LV_PREFIX + "vol2"
1265
  node_name = node.primary
1266
  AssertCommand(["lvcreate", "-L1G", "-n", lvname1, vgname], node=node_name)
1267
  AssertClusterVerify(fail=True, errors=[constants.CV_ENODEORPHANLV])
1268
  AssertCommand(["lvcreate", "-L1G", "-n", lvname2, vgname], node=node_name)
1269
  AssertClusterVerify(fail=True, errors=[constants.CV_ENODELVM,
1270
                                         constants.CV_ENODEORPHANLV])
1271
  AssertCommand(["lvremove", "-f", "/".join([vgname, lvname1])], node=node_name)
1272
  AssertCommand(["lvremove", "-f", "/".join([vgname, lvname2])], node=node_name)
1273
  AssertClusterVerify()