Statistics
| Branch: | Tag: | Revision:

root / qa / qa_cluster.py @ e8b919a1

History | View | Annotate | Download (20.6 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_utils
37
import qa_error
38

    
39
from qa_utils import AssertEqual, AssertCommand, GetCommandOutput
40

    
41

    
42
#: cluster verify command
43
_CLUSTER_VERIFY = ["gnt-cluster", "verify"]
44

    
45

    
46
def _RemoveFileFromAllNodes(filename):
47
  """Removes a file from all nodes.
48

49
  """
50
  for node in qa_config.get("nodes"):
51
    AssertCommand(["rm", "-f", filename], node=node)
52

    
53

    
54
def _CheckFileOnAllNodes(filename, content):
55
  """Verifies the content of the given file on all nodes.
56

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

    
62

    
63
# "gnt-cluster info" fields
64
_CIFIELD_RE = re.compile(r"^[-\s]*(?P<field>[^\s:]+):\s*(?P<value>\S.*)$")
65

    
66

    
67
def _GetBoolClusterField(field):
68
  """Get the Boolean value of a cluster field.
69

70
  This function currently assumes that the field name is unique in the cluster
71
  configuration. An assertion checks this assumption.
72

73
  @type field: string
74
  @param field: Name of the field
75
  @rtype: bool
76
  @return: The effective value of the field
77

78
  """
79
  master = qa_config.GetMasterNode()
80
  infocmd = "gnt-cluster info"
81
  info_out = qa_utils.GetCommandOutput(master["primary"], infocmd)
82
  ret = None
83
  for l in info_out.splitlines():
84
    m = _CIFIELD_RE.match(l)
85
    # FIXME: There should be a way to specify a field through a hierarchy
86
    if m and m.group("field") == field:
87
      # Make sure that ignoring the hierarchy doesn't cause a double match
88
      assert ret is None
89
      ret = (m.group("value").lower() == "true")
90
  if ret is not None:
91
    return ret
92
  raise qa_error.Error("Field not found in cluster configuration: %s" % field)
93

    
94

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

    
98

    
99
def _GetCVErrorCodes(cvout):
100
  ret = set()
101
  for l in cvout.splitlines():
102
    m = _CVERROR_RE.match(l)
103
    if m:
104
      ecode = m.group(1)
105
      ret.add(ecode)
106
  return ret
107

    
108

    
109
def AssertClusterVerify(fail=False, errors=None):
110
  """Run cluster-verify and check the result
111

112
  @type fail: bool
113
  @param fail: if cluster-verify is expected to fail instead of succeeding
114
  @type errors: list of tuples
115
  @param errors: List of CV_XXX errors that are expected; if specified, all the
116
      errors listed must appear in cluster-verify output. A non-empty value
117
      implies C{fail=True}.
118

119
  """
120
  cvcmd = "gnt-cluster verify"
121
  mnode = qa_config.GetMasterNode()
122
  if errors:
123
    cvout = GetCommandOutput(mnode["primary"], cvcmd + " --error-codes",
124
                             fail=True)
125
    actual = _GetCVErrorCodes(cvout)
126
    expected = compat.UniqueFrozenset(e for (_, e, _) in errors)
127
    if not actual.issuperset(expected):
128
      missing = expected.difference(actual)
129
      raise qa_error.Error("Cluster-verify didn't return these expected"
130
                           " errors: %s" % utils.CommaJoin(missing))
131
  else:
132
    AssertCommand(cvcmd, fail=fail, node=mnode)
133

    
134

    
135
# data for testing failures due to bad keys/values for disk parameters
136
_FAIL_PARAMS = ["nonexistent:resync-rate=1",
137
                "drbd:nonexistent=1",
138
                "drbd:resync-rate=invalid",
139
                ]
140

    
141

    
142
def TestClusterInitDisk():
143
  """gnt-cluster init -D"""
144
  name = qa_config.get("name")
145
  for param in _FAIL_PARAMS:
146
    AssertCommand(["gnt-cluster", "init", "-D", param, name], fail=True)
147

    
148

    
149
def TestClusterInit(rapi_user, rapi_secret):
150
  """gnt-cluster init"""
151
  master = qa_config.GetMasterNode()
152

    
153
  rapi_dir = os.path.dirname(pathutils.RAPI_USERS_FILE)
154

    
155
  # First create the RAPI credentials
156
  fh = tempfile.NamedTemporaryFile()
157
  try:
158
    fh.write("%s %s write\n" % (rapi_user, rapi_secret))
159
    fh.flush()
160

    
161
    tmpru = qa_utils.UploadFile(master["primary"], fh.name)
162
    try:
163
      AssertCommand(["mkdir", "-p", rapi_dir])
164
      AssertCommand(["mv", tmpru, pathutils.RAPI_USERS_FILE])
165
    finally:
166
      AssertCommand(["rm", "-f", tmpru])
167
  finally:
168
    fh.close()
169

    
170
  # Initialize cluster
171
  cmd = [
172
    "gnt-cluster", "init",
173
    "--primary-ip-version=%d" % qa_config.get("primary_ip_version", 4),
174
    "--enabled-hypervisors=%s" % ",".join(qa_config.GetEnabledHypervisors()),
175
    ]
176

    
177
  for spec_type in ("mem-size", "disk-size", "disk-count", "cpu-count",
178
                    "nic-count"):
179
    for spec_val in ("min", "max", "std"):
180
      spec = qa_config.get("ispec_%s_%s" %
181
                           (spec_type.replace("-", "_"), spec_val), None)
182
      if spec:
183
        cmd.append("--specs-%s=%s=%d" % (spec_type, spec_val, spec))
184

    
185
  if master.get("secondary", None):
186
    cmd.append("--secondary-ip=%s" % master["secondary"])
187

    
188
  master_netdev = qa_config.get("master-netdev", None)
189
  if master_netdev:
190
    cmd.append("--master-netdev=%s" % master_netdev)
191

    
192
  nicparams = qa_config.get("default-nicparams", None)
193
  if nicparams:
194
    cmd.append("--nic-parameters=%s" %
195
               ",".join(utils.FormatKeyValue(nicparams)))
196

    
197
  cmd.append(qa_config.get("name"))
198
  AssertCommand(cmd)
199

    
200
  cmd = ["gnt-cluster", "modify"]
201

    
202
  # hypervisor parameter modifications
203
  hvp = qa_config.get("hypervisor-parameters", {})
204
  for k, v in hvp.items():
205
    cmd.extend(["-H", "%s:%s" % (k, v)])
206
  # backend parameter modifications
207
  bep = qa_config.get("backend-parameters", "")
208
  if bep:
209
    cmd.extend(["-B", bep])
210

    
211
  if len(cmd) > 2:
212
    AssertCommand(cmd)
213

    
214
  # OS parameters
215
  osp = qa_config.get("os-parameters", {})
216
  for k, v in osp.items():
217
    AssertCommand(["gnt-os", "modify", "-O", v, k])
218

    
219
  # OS hypervisor parameters
220
  os_hvp = qa_config.get("os-hvp", {})
221
  for os_name in os_hvp:
222
    for hv, hvp in os_hvp[os_name].items():
223
      AssertCommand(["gnt-os", "modify", "-H", "%s:%s" % (hv, hvp), os_name])
224

    
225

    
226
def TestClusterRename():
227
  """gnt-cluster rename"""
228
  cmd = ["gnt-cluster", "rename", "-f"]
229

    
230
  original_name = qa_config.get("name")
231
  rename_target = qa_config.get("rename", None)
232
  if rename_target is None:
233
    print qa_utils.FormatError('"rename" entry is missing')
234
    return
235

    
236
  for data in [
237
    cmd + [rename_target],
238
    _CLUSTER_VERIFY,
239
    cmd + [original_name],
240
    _CLUSTER_VERIFY,
241
    ]:
242
    AssertCommand(data)
243

    
244

    
245
def TestClusterOob():
246
  """out-of-band framework"""
247
  oob_path_exists = "/tmp/ganeti-qa-oob-does-exist-%s" % utils.NewUUID()
248

    
249
  AssertCommand(_CLUSTER_VERIFY)
250
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
251
                 "oob_program=/tmp/ganeti-qa-oob-does-not-exist-%s" %
252
                 utils.NewUUID()])
253

    
254
  AssertCommand(_CLUSTER_VERIFY, fail=True)
255

    
256
  AssertCommand(["touch", oob_path_exists])
257
  AssertCommand(["chmod", "0400", oob_path_exists])
258
  AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
259

    
260
  try:
261
    AssertCommand(["gnt-cluster", "modify", "--node-parameters",
262
                   "oob_program=%s" % oob_path_exists])
263

    
264
    AssertCommand(_CLUSTER_VERIFY, fail=True)
265

    
266
    AssertCommand(["chmod", "0500", oob_path_exists])
267
    AssertCommand(["gnt-cluster", "copyfile", oob_path_exists])
268

    
269
    AssertCommand(_CLUSTER_VERIFY)
270
  finally:
271
    AssertCommand(["gnt-cluster", "command", "rm", oob_path_exists])
272

    
273
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
274
                 "oob_program="])
275

    
276

    
277
def TestClusterEpo():
278
  """gnt-cluster epo"""
279
  master = qa_config.GetMasterNode()
280

    
281
  # Assert that OOB is unavailable for all nodes
282
  result_output = GetCommandOutput(master["primary"],
283
                                   "gnt-node list --verbose --no-headers -o"
284
                                   " powered")
285
  AssertEqual(compat.all(powered == "(unavail)"
286
                         for powered in result_output.splitlines()), True)
287

    
288
  # Conflicting
289
  AssertCommand(["gnt-cluster", "epo", "--groups", "--all"], fail=True)
290
  # --all doesn't expect arguments
291
  AssertCommand(["gnt-cluster", "epo", "--all", "some_arg"], fail=True)
292

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

    
296
  # This shouldn't fail
297
  AssertCommand(["gnt-cluster", "epo", "-f", "--all"])
298

    
299
  # All instances should have been stopped now
300
  result_output = GetCommandOutput(master["primary"],
301
                                   "gnt-instance list --no-headers -o status")
302
  # ERROR_down because the instance is stopped but not recorded as such
303
  AssertEqual(compat.all(status == "ERROR_down"
304
                         for status in result_output.splitlines()), True)
305

    
306
  # Now start everything again
307
  AssertCommand(["gnt-cluster", "epo", "--on", "-f", "--all"])
308

    
309
  # All instances should have been started now
310
  result_output = GetCommandOutput(master["primary"],
311
                                   "gnt-instance list --no-headers -o status")
312
  AssertEqual(compat.all(status == "running"
313
                         for status in result_output.splitlines()), True)
314

    
315

    
316
def TestClusterVerify():
317
  """gnt-cluster verify"""
318
  AssertCommand(_CLUSTER_VERIFY)
319
  AssertCommand(["gnt-cluster", "verify-disks"])
320

    
321

    
322
def TestJobqueue():
323
  """gnt-debug test-jobqueue"""
324
  AssertCommand(["gnt-debug", "test-jobqueue"])
325

    
326

    
327
def TestDelay(node):
328
  """gnt-debug delay"""
329
  AssertCommand(["gnt-debug", "delay", "1"])
330
  AssertCommand(["gnt-debug", "delay", "--no-master", "1"])
331
  AssertCommand(["gnt-debug", "delay", "--no-master",
332
                 "-n", node["primary"], "1"])
333

    
334

    
335
def TestClusterReservedLvs():
336
  """gnt-cluster reserved lvs"""
337
  for fail, cmd in [
338
    (False, _CLUSTER_VERIFY),
339
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
340
    (False, ["lvcreate", "-L1G", "-nqa-test", "xenvg"]),
341
    (True, _CLUSTER_VERIFY),
342
    (False, ["gnt-cluster", "modify", "--reserved-lvs",
343
             "xenvg/qa-test,.*/other-test"]),
344
    (False, _CLUSTER_VERIFY),
345
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ".*/qa-.*"]),
346
    (False, _CLUSTER_VERIFY),
347
    (False, ["gnt-cluster", "modify", "--reserved-lvs", ""]),
348
    (True, _CLUSTER_VERIFY),
349
    (False, ["lvremove", "-f", "xenvg/qa-test"]),
350
    (False, _CLUSTER_VERIFY),
351
    ]:
352
    AssertCommand(cmd, fail=fail)
353

    
354

    
355
def TestClusterModifyEmpty():
356
  """gnt-cluster modify"""
357
  AssertCommand(["gnt-cluster", "modify"], fail=True)
358

    
359

    
360
def TestClusterModifyDisk():
361
  """gnt-cluster modify -D"""
362
  for param in _FAIL_PARAMS:
363
    AssertCommand(["gnt-cluster", "modify", "-D", param], fail=True)
364

    
365

    
366
def TestClusterModifyBe():
367
  """gnt-cluster modify -B"""
368
  for fail, cmd in [
369
    # max/min mem
370
    (False, ["gnt-cluster", "modify", "-B", "maxmem=256"]),
371
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *maxmem: 256$'"]),
372
    (False, ["gnt-cluster", "modify", "-B", "minmem=256"]),
373
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *minmem: 256$'"]),
374
    (True, ["gnt-cluster", "modify", "-B", "maxmem=a"]),
375
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *maxmem: 256$'"]),
376
    (True, ["gnt-cluster", "modify", "-B", "minmem=a"]),
377
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *minmem: 256$'"]),
378
    (False, ["gnt-cluster", "modify", "-B", "maxmem=128,minmem=128"]),
379
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *maxmem: 128$'"]),
380
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *minmem: 128$'"]),
381
    # vcpus
382
    (False, ["gnt-cluster", "modify", "-B", "vcpus=4"]),
383
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 4$'"]),
384
    (True, ["gnt-cluster", "modify", "-B", "vcpus=a"]),
385
    (False, ["gnt-cluster", "modify", "-B", "vcpus=1"]),
386
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *vcpus: 1$'"]),
387
    # auto_balance
388
    (False, ["gnt-cluster", "modify", "-B", "auto_balance=False"]),
389
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: False$'"]),
390
    (True, ["gnt-cluster", "modify", "-B", "auto_balance=1"]),
391
    (False, ["gnt-cluster", "modify", "-B", "auto_balance=True"]),
392
    (False, ["sh", "-c", "gnt-cluster info|grep '^ *auto_balance: True$'"]),
393
    ]:
394
    AssertCommand(cmd, fail=fail)
395

    
396
  # redo the original-requested BE parameters, if any
397
  bep = qa_config.get("backend-parameters", "")
398
  if bep:
399
    AssertCommand(["gnt-cluster", "modify", "-B", bep])
400

    
401

    
402
def TestClusterInfo():
403
  """gnt-cluster info"""
404
  AssertCommand(["gnt-cluster", "info"])
405

    
406

    
407
def TestClusterRedistConf():
408
  """gnt-cluster redist-conf"""
409
  AssertCommand(["gnt-cluster", "redist-conf"])
410

    
411

    
412
def TestClusterGetmaster():
413
  """gnt-cluster getmaster"""
414
  AssertCommand(["gnt-cluster", "getmaster"])
415

    
416

    
417
def TestClusterVersion():
418
  """gnt-cluster version"""
419
  AssertCommand(["gnt-cluster", "version"])
420

    
421

    
422
def TestClusterRenewCrypto():
423
  """gnt-cluster renew-crypto"""
424
  master = qa_config.GetMasterNode()
425

    
426
  # Conflicting options
427
  cmd = ["gnt-cluster", "renew-crypto", "--force",
428
         "--new-cluster-certificate", "--new-confd-hmac-key"]
429
  conflicting = [
430
    ["--new-rapi-certificate", "--rapi-certificate=/dev/null"],
431
    ["--new-cluster-domain-secret", "--cluster-domain-secret=/dev/null"],
432
    ]
433
  for i in conflicting:
434
    AssertCommand(cmd + i, fail=True)
435

    
436
  # Invalid RAPI certificate
437
  cmd = ["gnt-cluster", "renew-crypto", "--force",
438
         "--rapi-certificate=/dev/null"]
439
  AssertCommand(cmd, fail=True)
440

    
441
  rapi_cert_backup = qa_utils.BackupFile(master["primary"],
442
                                         pathutils.RAPI_CERT_FILE)
443
  try:
444
    # Custom RAPI certificate
445
    fh = tempfile.NamedTemporaryFile()
446

    
447
    # Ensure certificate doesn't cause "gnt-cluster verify" to complain
448
    validity = constants.SSL_CERT_EXPIRATION_WARN * 3
449

    
450
    utils.GenerateSelfSignedSslCert(fh.name, validity=validity)
451

    
452
    tmpcert = qa_utils.UploadFile(master["primary"], fh.name)
453
    try:
454
      AssertCommand(["gnt-cluster", "renew-crypto", "--force",
455
                     "--rapi-certificate=%s" % tmpcert])
456
    finally:
457
      AssertCommand(["rm", "-f", tmpcert])
458

    
459
    # Custom cluster domain secret
460
    cds_fh = tempfile.NamedTemporaryFile()
461
    cds_fh.write(utils.GenerateSecret())
462
    cds_fh.write("\n")
463
    cds_fh.flush()
464

    
465
    tmpcds = qa_utils.UploadFile(master["primary"], cds_fh.name)
466
    try:
467
      AssertCommand(["gnt-cluster", "renew-crypto", "--force",
468
                     "--cluster-domain-secret=%s" % tmpcds])
469
    finally:
470
      AssertCommand(["rm", "-f", tmpcds])
471

    
472
    # Normal case
473
    AssertCommand(["gnt-cluster", "renew-crypto", "--force",
474
                   "--new-cluster-certificate", "--new-confd-hmac-key",
475
                   "--new-rapi-certificate", "--new-cluster-domain-secret"])
476

    
477
    # Restore RAPI certificate
478
    AssertCommand(["gnt-cluster", "renew-crypto", "--force",
479
                   "--rapi-certificate=%s" % rapi_cert_backup])
480
  finally:
481
    AssertCommand(["rm", "-f", rapi_cert_backup])
482

    
483

    
484
def TestClusterBurnin():
485
  """Burnin"""
486
  master = qa_config.GetMasterNode()
487

    
488
  options = qa_config.get("options", {})
489
  disk_template = options.get("burnin-disk-template", "drbd")
490
  parallel = options.get("burnin-in-parallel", False)
491
  check_inst = options.get("burnin-check-instances", False)
492
  do_rename = options.get("burnin-rename", "")
493
  do_reboot = options.get("burnin-reboot", True)
494
  reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
495

    
496
  # Get as many instances as we need
497
  instances = []
498
  try:
499
    try:
500
      num = qa_config.get("options", {}).get("burnin-instances", 1)
501
      for _ in range(0, num):
502
        instances.append(qa_config.AcquireInstance())
503
    except qa_error.OutOfInstancesError:
504
      print "Not enough instances, continuing anyway."
505

    
506
    if len(instances) < 1:
507
      raise qa_error.Error("Burnin needs at least one instance")
508

    
509
    script = qa_utils.UploadFile(master["primary"], "../tools/burnin")
510
    try:
511
      # Run burnin
512
      cmd = [script,
513
             "--os=%s" % qa_config.get("os"),
514
             "--minmem-size=%s" % qa_config.get(constants.BE_MINMEM),
515
             "--maxmem-size=%s" % qa_config.get(constants.BE_MAXMEM),
516
             "--disk-size=%s" % ",".join(qa_config.get("disk")),
517
             "--disk-growth=%s" % ",".join(qa_config.get("disk-growth")),
518
             "--disk-template=%s" % disk_template]
519
      if parallel:
520
        cmd.append("--parallel")
521
        cmd.append("--early-release")
522
      if check_inst:
523
        cmd.append("--http-check")
524
      if do_rename:
525
        cmd.append("--rename=%s" % do_rename)
526
      if not do_reboot:
527
        cmd.append("--no-reboot")
528
      else:
529
        cmd.append("--reboot-types=%s" % ",".join(reboot_types))
530
      cmd += [inst["name"] for inst in instances]
531
      AssertCommand(cmd)
532
    finally:
533
      AssertCommand(["rm", "-f", script])
534

    
535
  finally:
536
    for inst in instances:
537
      qa_config.ReleaseInstance(inst)
538

    
539

    
540
def TestClusterMasterFailover():
541
  """gnt-cluster master-failover"""
542
  master = qa_config.GetMasterNode()
543
  failovermaster = qa_config.AcquireNode(exclude=master)
544

    
545
  cmd = ["gnt-cluster", "master-failover"]
546
  try:
547
    AssertCommand(cmd, node=failovermaster)
548
    # Back to original master node
549
    AssertCommand(cmd, node=master)
550
  finally:
551
    qa_config.ReleaseNode(failovermaster)
552

    
553

    
554
def TestClusterMasterFailoverWithDrainedQueue():
555
  """gnt-cluster master-failover with drained queue"""
556
  drain_check = ["test", "-f", pathutils.JOB_QUEUE_DRAIN_FILE]
557

    
558
  master = qa_config.GetMasterNode()
559
  failovermaster = qa_config.AcquireNode(exclude=master)
560

    
561
  # Ensure queue is not drained
562
  for node in [master, failovermaster]:
563
    AssertCommand(drain_check, node=node, fail=True)
564

    
565
  # Drain queue on failover master
566
  AssertCommand(["touch", pathutils.JOB_QUEUE_DRAIN_FILE], node=failovermaster)
567

    
568
  cmd = ["gnt-cluster", "master-failover"]
569
  try:
570
    AssertCommand(drain_check, node=failovermaster)
571
    AssertCommand(cmd, node=failovermaster)
572
    AssertCommand(drain_check, fail=True)
573
    AssertCommand(drain_check, node=failovermaster, fail=True)
574

    
575
    # Back to original master node
576
    AssertCommand(cmd, node=master)
577
  finally:
578
    qa_config.ReleaseNode(failovermaster)
579

    
580
  AssertCommand(drain_check, fail=True)
581
  AssertCommand(drain_check, node=failovermaster, fail=True)
582

    
583

    
584
def TestClusterCopyfile():
585
  """gnt-cluster copyfile"""
586
  master = qa_config.GetMasterNode()
587

    
588
  uniqueid = utils.NewUUID()
589

    
590
  # Create temporary file
591
  f = tempfile.NamedTemporaryFile()
592
  f.write(uniqueid)
593
  f.flush()
594
  f.seek(0)
595

    
596
  # Upload file to master node
597
  testname = qa_utils.UploadFile(master["primary"], f.name)
598
  try:
599
    # Copy file to all nodes
600
    AssertCommand(["gnt-cluster", "copyfile", testname])
601
    _CheckFileOnAllNodes(testname, uniqueid)
602
  finally:
603
    _RemoveFileFromAllNodes(testname)
604

    
605

    
606
def TestClusterCommand():
607
  """gnt-cluster command"""
608
  uniqueid = utils.NewUUID()
609
  rfile = "/tmp/gnt%s" % utils.NewUUID()
610
  rcmd = utils.ShellQuoteArgs(["echo", "-n", uniqueid])
611
  cmd = utils.ShellQuoteArgs(["gnt-cluster", "command",
612
                              "%s >%s" % (rcmd, rfile)])
613

    
614
  try:
615
    AssertCommand(cmd)
616
    _CheckFileOnAllNodes(rfile, uniqueid)
617
  finally:
618
    _RemoveFileFromAllNodes(rfile)
619

    
620

    
621
def TestClusterDestroy():
622
  """gnt-cluster destroy"""
623
  AssertCommand(["gnt-cluster", "destroy", "--yes-do-it"])
624

    
625

    
626
def TestClusterRepairDiskSizes():
627
  """gnt-cluster repair-disk-sizes"""
628
  AssertCommand(["gnt-cluster", "repair-disk-sizes"])
629

    
630

    
631
def TestSetExclStorCluster(newvalue):
632
  """Set the exclusive_storage node parameter at the cluster level.
633

634
  @type newvalue: bool
635
  @param newvalue: New value of exclusive_storage
636
  @rtype: bool
637
  @return: The old value of exclusive_storage
638

639
  """
640
  oldvalue = _GetBoolClusterField("exclusive_storage")
641
  AssertCommand(["gnt-cluster", "modify", "--node-parameters",
642
                 "exclusive_storage=%s" % newvalue])
643
  effvalue = _GetBoolClusterField("exclusive_storage")
644
  if effvalue != newvalue:
645
    raise qa_error.Error("exclusive_storage has the wrong value: %s instead"
646
                         " of %s" % (effvalue, newvalue))
647
  return oldvalue
648

    
649

    
650
def _BuildSetESCmd(value, node_name):
651
  return ["gnt-node", "modify", "--node-parameters",
652
          "exclusive_storage=%s" % value, node_name]
653

    
654

    
655
def TestExclStorSingleNode(node):
656
  """cluster-verify reports exclusive_storage set only on one node.
657

658
  """
659
  node_name = node["primary"]
660
  es_val = _GetBoolClusterField("exclusive_storage")
661
  assert not es_val
662
  AssertCommand(_BuildSetESCmd(True, node_name))
663
  AssertClusterVerify(fail=True, errors=[constants.CV_EGROUPMIXEDESFLAG])
664
  AssertCommand(_BuildSetESCmd("default", node_name))
665
  AssertClusterVerify()