Statistics
| Branch: | Tag: | Revision:

root / qa / qa_instance.py @ e4c346a5

History | View | Annotate | Download (21.9 kB)

1
#
2
#
3

    
4
# Copyright (C) 2007, 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
"""Instance related QA tests.
23

24
"""
25

    
26
import re
27

    
28
from ganeti import utils
29
from ganeti import constants
30
from ganeti import query
31
from ganeti import pathutils
32

    
33
import qa_config
34
import qa_utils
35
import qa_error
36

    
37
from qa_utils import AssertIn, AssertCommand, AssertEqual
38
from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG, RETURN_VALUE
39

    
40

    
41
def _GetDiskStatePath(disk):
42
  return "/sys/block/%s/device/state" % disk
43

    
44

    
45
def _GetGenericAddParameters(inst, force_mac=None):
46
  params = ["-B"]
47
  params.append("%s=%s,%s=%s" % (constants.BE_MINMEM,
48
                                 qa_config.get(constants.BE_MINMEM),
49
                                 constants.BE_MAXMEM,
50
                                 qa_config.get(constants.BE_MAXMEM)))
51
  for idx, size in enumerate(qa_config.get("disk")):
52
    params.extend(["--disk", "%s:size=%s" % (idx, size)])
53

    
54
  # Set static MAC address if configured
55
  if force_mac:
56
    nic0_mac = force_mac
57
  else:
58
    nic0_mac = qa_config.GetInstanceNicMac(inst)
59
  if nic0_mac:
60
    params.extend(["--net", "0:mac=%s" % nic0_mac])
61

    
62
  return params
63

    
64

    
65
def _DiskTest(node, disk_template):
66
  instance = qa_config.AcquireInstance()
67
  try:
68
    cmd = (["gnt-instance", "add",
69
            "--os-type=%s" % qa_config.get("os"),
70
            "--disk-template=%s" % disk_template,
71
            "--node=%s" % node] +
72
           _GetGenericAddParameters(instance))
73
    cmd.append(instance["name"])
74

    
75
    AssertCommand(cmd)
76

    
77
    _CheckSsconfInstanceList(instance["name"])
78

    
79
    return instance
80
  except:
81
    qa_config.ReleaseInstance(instance)
82
    raise
83

    
84

    
85
def _GetInstanceInfo(instance):
86
  """Return information about the actual state of an instance.
87

88
  @type instance: string
89
  @param instance: the instance name
90
  @return: a dictionary with two keys:
91
      - "nodes": instance nodes, a list of strings
92
      - "volumes": instance volume IDs, a list of strings
93

94
  """
95
  master = qa_config.GetMasterNode()
96
  infocmd = utils.ShellQuoteArgs(["gnt-instance", "info", instance])
97
  info_out = qa_utils.GetCommandOutput(master["primary"], infocmd)
98
  re_node = re.compile(r"^\s+-\s+(?:primary|secondaries):\s+(\S.+)$")
99
  node_elem = r"([^,()]+)(?:\s+\([^)]+\))?"
100
  # re_nodelist matches a list of nodes returned by gnt-instance info, e.g.:
101
  #  node1.fqdn
102
  #  node2.fqdn,node3.fqdn
103
  #  node4.fqdn (group mygroup, group UUID 01234567-abcd-0123-4567-0123456789ab)
104
  # FIXME This works with no more than 2 secondaries
105
  re_nodelist = re.compile(node_elem + "(?:," + node_elem + ")?$")
106
  re_vol = re.compile(r"^\s+logical_id:\s+(\S+)$")
107
  nodes = []
108
  vols = []
109
  for line in info_out.splitlines():
110
    m = re_node.match(line)
111
    if m:
112
      nodestr = m.group(1)
113
      m2 = re_nodelist.match(nodestr)
114
      if m2:
115
        nodes.extend(filter(None, m2.groups()))
116
      else:
117
        nodes.append(nodestr)
118
    m = re_vol.match(line)
119
    if m:
120
      vols.append(m.group(1))
121
  assert vols
122
  assert nodes
123
  return {"nodes": nodes, "volumes": vols}
124

    
125

    
126
def _DestroyInstanceVolumes(instance):
127
  """Remove all the LVM volumes of an instance.
128

129
  This is used to simulate HW errors (dead nodes, broken disks...); the
130
  configuration of the instance is not affected.
131
  @type instance: dictionary
132
  @param instance: the instance
133

134
  """
135
  info = _GetInstanceInfo(instance["name"])
136
  vols = info["volumes"]
137
  for node in info["nodes"]:
138
    AssertCommand(["lvremove", "-f"] + vols, node=node)
139

    
140

    
141
def _GetBoolInstanceField(instance, field):
142
  """Get the Boolean value of a field of an instance.
143

144
  @type instance: string
145
  @param instance: Instance name
146
  @type field: string
147
  @param field: Name of the field
148

149
  """
150
  master = qa_config.GetMasterNode()
151
  infocmd = utils.ShellQuoteArgs(["gnt-instance", "list", "--no-headers",
152
                                  "-o", field, instance])
153
  info_out = qa_utils.GetCommandOutput(master["primary"], infocmd).strip()
154
  if info_out == "Y":
155
    return True
156
  elif info_out == "N":
157
    return False
158
  else:
159
    raise qa_error.Error("Field %s of instance %s has a non-Boolean value:"
160
                         " %s" % (field, instance, info_out))
161

    
162

    
163
@InstanceCheck(None, INST_UP, RETURN_VALUE)
164
def TestInstanceAddWithPlainDisk(node):
165
  """gnt-instance add -t plain"""
166
  return _DiskTest(node["primary"], "plain")
167

    
168

    
169
@InstanceCheck(None, INST_UP, RETURN_VALUE)
170
def TestInstanceAddWithDrbdDisk(node, node2):
171
  """gnt-instance add -t drbd"""
172
  return _DiskTest("%s:%s" % (node["primary"], node2["primary"]),
173
                   "drbd")
174

    
175

    
176
@InstanceCheck(None, INST_DOWN, FIRST_ARG)
177
def TestInstanceRemove(instance):
178
  """gnt-instance remove"""
179
  AssertCommand(["gnt-instance", "remove", "-f", instance["name"]])
180

    
181
  qa_config.ReleaseInstance(instance)
182

    
183

    
184
@InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
185
def TestInstanceStartup(instance):
186
  """gnt-instance startup"""
187
  AssertCommand(["gnt-instance", "startup", instance["name"]])
188

    
189

    
190
@InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
191
def TestInstanceShutdown(instance):
192
  """gnt-instance shutdown"""
193
  AssertCommand(["gnt-instance", "shutdown", instance["name"]])
194

    
195

    
196
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
197
def TestInstanceReboot(instance):
198
  """gnt-instance reboot"""
199
  options = qa_config.get("options", {})
200
  reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
201
  name = instance["name"]
202
  for rtype in reboot_types:
203
    AssertCommand(["gnt-instance", "reboot", "--type=%s" % rtype, name])
204

    
205
  AssertCommand(["gnt-instance", "shutdown", name])
206
  qa_utils.RunInstanceCheck(instance, False)
207
  AssertCommand(["gnt-instance", "reboot", name])
208

    
209
  master = qa_config.GetMasterNode()
210
  cmd = ["gnt-instance", "list", "--no-headers", "-o", "status", name]
211
  result_output = qa_utils.GetCommandOutput(master["primary"],
212
                                            utils.ShellQuoteArgs(cmd))
213
  AssertEqual(result_output.strip(), constants.INSTST_RUNNING)
214

    
215

    
216
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
217
def TestInstanceReinstall(instance):
218
  """gnt-instance reinstall"""
219
  AssertCommand(["gnt-instance", "reinstall", "-f", instance["name"]])
220

    
221
  # Test with non-existant OS definition
222
  AssertCommand(["gnt-instance", "reinstall", "-f",
223
                 "--os-type=NonExistantOsForQa",
224
                 instance["name"]],
225
                fail=True)
226

    
227

    
228
def _ReadSsconfInstanceList():
229
  """Reads ssconf_instance_list from the master node.
230

231
  """
232
  master = qa_config.GetMasterNode()
233

    
234
  cmd = ["cat", utils.PathJoin(pathutils.DATA_DIR,
235
                               "ssconf_%s" % constants.SS_INSTANCE_LIST)]
236

    
237
  return qa_utils.GetCommandOutput(master["primary"],
238
                                   utils.ShellQuoteArgs(cmd)).splitlines()
239

    
240

    
241
def _CheckSsconfInstanceList(instance):
242
  """Checks if a certain instance is in the ssconf instance list.
243

244
  @type instance: string
245
  @param instance: Instance name
246

247
  """
248
  AssertIn(qa_utils.ResolveInstanceName(instance),
249
           _ReadSsconfInstanceList())
250

    
251

    
252
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
253
def TestInstanceRenameAndBack(rename_source, rename_target):
254
  """gnt-instance rename
255

256
  This must leave the instance with the original name, not the target
257
  name.
258

259
  """
260
  _CheckSsconfInstanceList(rename_source)
261

    
262
  # first do a rename to a different actual name, expecting it to fail
263
  qa_utils.AddToEtcHosts(["meeeeh-not-exists", rename_target])
264
  try:
265
    AssertCommand(["gnt-instance", "rename", rename_source, rename_target],
266
                  fail=True)
267
    _CheckSsconfInstanceList(rename_source)
268
  finally:
269
    qa_utils.RemoveFromEtcHosts(["meeeeh-not-exists", rename_target])
270

    
271
  # Check instance volume tags correctly updated
272
  # FIXME: this is LVM specific!
273
  info = _GetInstanceInfo(rename_source)
274
  tags_cmd = ("lvs -o tags --noheadings %s | grep " %
275
              (" ".join(info["volumes"]), ))
276

    
277
  # and now rename instance to rename_target...
278
  AssertCommand(["gnt-instance", "rename", rename_source, rename_target])
279
  _CheckSsconfInstanceList(rename_target)
280
  qa_utils.RunInstanceCheck(rename_source, False)
281
  qa_utils.RunInstanceCheck(rename_target, False)
282

    
283
  # NOTE: tags might not be the exactly as the instance name, due to
284
  # charset restrictions; hence the test might be flaky
285
  if rename_source != rename_target:
286
    for node in info["nodes"]:
287
      AssertCommand(tags_cmd + rename_source, node=node, fail=True)
288
      AssertCommand(tags_cmd + rename_target, node=node, fail=False)
289

    
290
  # and back
291
  AssertCommand(["gnt-instance", "rename", rename_target, rename_source])
292
  _CheckSsconfInstanceList(rename_source)
293
  qa_utils.RunInstanceCheck(rename_target, False)
294

    
295
  if rename_source != rename_target:
296
    for node in info["nodes"]:
297
      AssertCommand(tags_cmd + rename_source, node=node, fail=False)
298
      AssertCommand(tags_cmd + rename_target, node=node, fail=True)
299

    
300

    
301
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
302
def TestInstanceFailover(instance):
303
  """gnt-instance failover"""
304
  cmd = ["gnt-instance", "failover", "--force", instance["name"]]
305

    
306
  # failover ...
307
  AssertCommand(cmd)
308
  qa_utils.RunInstanceCheck(instance, True)
309

    
310
  # ... and back
311
  AssertCommand(cmd)
312

    
313

    
314
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
315
def TestInstanceMigrate(instance, toggle_always_failover=True):
316
  """gnt-instance migrate"""
317
  cmd = ["gnt-instance", "migrate", "--force", instance["name"]]
318
  af_par = constants.BE_ALWAYS_FAILOVER
319
  af_field = "be/" + constants.BE_ALWAYS_FAILOVER
320
  af_init_val = _GetBoolInstanceField(instance["name"], af_field)
321

    
322
  # migrate ...
323
  AssertCommand(cmd)
324
  # TODO: Verify the choice between failover and migration
325
  qa_utils.RunInstanceCheck(instance, True)
326

    
327
  # ... and back (possibly with always_failover toggled)
328
  if toggle_always_failover:
329
    AssertCommand(["gnt-instance", "modify", "-B",
330
                   ("%s=%s" % (af_par, not af_init_val)),
331
                   instance["name"]])
332
  AssertCommand(cmd)
333
  # TODO: Verify the choice between failover and migration
334
  qa_utils.RunInstanceCheck(instance, True)
335
  if toggle_always_failover:
336
    AssertCommand(["gnt-instance", "modify", "-B",
337
                   ("%s=%s" % (af_par, af_init_val)), instance["name"]])
338

    
339
  # TODO: Split into multiple tests
340
  AssertCommand(["gnt-instance", "shutdown", instance["name"]])
341
  qa_utils.RunInstanceCheck(instance, False)
342
  AssertCommand(cmd, fail=True)
343
  AssertCommand(["gnt-instance", "migrate", "--force", "--allow-failover",
344
                 instance["name"]])
345
  AssertCommand(["gnt-instance", "start", instance["name"]])
346
  AssertCommand(cmd)
347
  # @InstanceCheck enforces the check that the instance is running
348
  qa_utils.RunInstanceCheck(instance, True)
349

    
350
  AssertCommand(["gnt-instance", "modify", "-B",
351
                 ("%s=%s" %
352
                  (constants.BE_ALWAYS_FAILOVER, constants.VALUE_TRUE)),
353
                 instance["name"]])
354

    
355
  AssertCommand(cmd)
356
  qa_utils.RunInstanceCheck(instance, True)
357
  # TODO: Verify that a failover has been done instead of a migration
358

    
359
  # TODO: Verify whether the default value is restored here (not hardcoded)
360
  AssertCommand(["gnt-instance", "modify", "-B",
361
                 ("%s=%s" %
362
                  (constants.BE_ALWAYS_FAILOVER, constants.VALUE_FALSE)),
363
                 instance["name"]])
364

    
365
  AssertCommand(cmd)
366
  qa_utils.RunInstanceCheck(instance, True)
367

    
368

    
369
def TestInstanceInfo(instance):
370
  """gnt-instance info"""
371
  AssertCommand(["gnt-instance", "info", instance["name"]])
372

    
373

    
374
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
375
def TestInstanceModify(instance):
376
  """gnt-instance modify"""
377
  default_hv = qa_config.GetDefaultHypervisor()
378

    
379
  # Assume /sbin/init exists on all systems
380
  test_kernel = "/sbin/init"
381
  test_initrd = test_kernel
382

    
383
  orig_maxmem = qa_config.get(constants.BE_MAXMEM)
384
  orig_minmem = qa_config.get(constants.BE_MINMEM)
385
  #orig_bridge = qa_config.get("bridge", "xen-br0")
386

    
387
  args = [
388
    ["-B", "%s=128" % constants.BE_MINMEM],
389
    ["-B", "%s=128" % constants.BE_MAXMEM],
390
    ["-B", "%s=%s,%s=%s" % (constants.BE_MINMEM, orig_minmem,
391
                            constants.BE_MAXMEM, orig_maxmem)],
392
    ["-B", "%s=2" % constants.BE_VCPUS],
393
    ["-B", "%s=1" % constants.BE_VCPUS],
394
    ["-B", "%s=%s" % (constants.BE_VCPUS, constants.VALUE_DEFAULT)],
395
    ["-B", "%s=%s" % (constants.BE_ALWAYS_FAILOVER, constants.VALUE_TRUE)],
396
    ["-B", "%s=%s" % (constants.BE_ALWAYS_FAILOVER, constants.VALUE_DEFAULT)],
397

    
398
    ["-H", "%s=%s" % (constants.HV_KERNEL_PATH, test_kernel)],
399
    ["-H", "%s=%s" % (constants.HV_KERNEL_PATH, constants.VALUE_DEFAULT)],
400

    
401
    # TODO: bridge tests
402
    #["--bridge", "xen-br1"],
403
    #["--bridge", orig_bridge],
404
    ]
405

    
406
  if default_hv == constants.HT_XEN_PVM:
407
    args.extend([
408
      ["-H", "%s=%s" % (constants.HV_INITRD_PATH, test_initrd)],
409
      ["-H", "no_%s" % (constants.HV_INITRD_PATH, )],
410
      ["-H", "%s=%s" % (constants.HV_INITRD_PATH, constants.VALUE_DEFAULT)],
411
      ])
412
  elif default_hv == constants.HT_XEN_HVM:
413
    args.extend([
414
      ["-H", "%s=acn" % constants.HV_BOOT_ORDER],
415
      ["-H", "%s=%s" % (constants.HV_BOOT_ORDER, constants.VALUE_DEFAULT)],
416
      ])
417

    
418
  for alist in args:
419
    AssertCommand(["gnt-instance", "modify"] + alist + [instance["name"]])
420

    
421
  # check no-modify
422
  AssertCommand(["gnt-instance", "modify", instance["name"]], fail=True)
423

    
424
  # Marking offline while instance is running must fail...
425
  AssertCommand(["gnt-instance", "modify", "--offline", instance["name"]],
426
                 fail=True)
427

    
428
  # ...while making it online is ok, and should work
429
  AssertCommand(["gnt-instance", "modify", "--online", instance["name"]])
430

    
431

    
432
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
433
def TestInstanceStoppedModify(instance):
434
  """gnt-instance modify (stopped instance)"""
435
  name = instance["name"]
436

    
437
  # Instance was not marked offline; try marking it online once more
438
  AssertCommand(["gnt-instance", "modify", "--online", name])
439

    
440
  # Mark instance as offline
441
  AssertCommand(["gnt-instance", "modify", "--offline", name])
442

    
443
  # When the instance is offline shutdown should only work with --force,
444
  # while start should never work
445
  AssertCommand(["gnt-instance", "shutdown", name], fail=True)
446
  AssertCommand(["gnt-instance", "shutdown", "--force", name])
447
  AssertCommand(["gnt-instance", "start", name], fail=True)
448
  AssertCommand(["gnt-instance", "start", "--force", name], fail=True)
449

    
450
  # Also do offline to offline
451
  AssertCommand(["gnt-instance", "modify", "--offline", name])
452

    
453
  # And online again
454
  AssertCommand(["gnt-instance", "modify", "--online", name])
455

    
456

    
457
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
458
def TestInstanceConvertDisk(instance, snode):
459
  """gnt-instance modify -t"""
460
  name = instance["name"]
461
  AssertCommand(["gnt-instance", "modify", "-t", "plain", name])
462
  AssertCommand(["gnt-instance", "modify", "-t", "drbd",
463
                 "-n", snode["primary"], name])
464

    
465

    
466
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
467
def TestInstanceGrowDisk(instance):
468
  """gnt-instance grow-disk"""
469
  name = instance["name"]
470
  all_size = qa_config.get("disk")
471
  all_grow = qa_config.get("disk-growth")
472
  if not all_grow:
473
    # missing disk sizes but instance grow disk has been enabled,
474
    # let's set fixed/nomimal growth
475
    all_grow = ["128M" for _ in all_size]
476
  for idx, (size, grow) in enumerate(zip(all_size, all_grow)):
477
    # succeed in grow by amount
478
    AssertCommand(["gnt-instance", "grow-disk", name, str(idx), grow])
479
    # fail in grow to the old size
480
    AssertCommand(["gnt-instance", "grow-disk", "--absolute", name, str(idx),
481
                   size], fail=True)
482
    # succeed to grow to old size + 2 * growth
483
    int_size = utils.ParseUnit(size)
484
    int_grow = utils.ParseUnit(grow)
485
    AssertCommand(["gnt-instance", "grow-disk", "--absolute", name, str(idx),
486
                   str(int_size + 2 * int_grow)])
487

    
488

    
489
def TestInstanceList():
490
  """gnt-instance list"""
491
  qa_utils.GenericQueryTest("gnt-instance", query.INSTANCE_FIELDS.keys())
492

    
493

    
494
def TestInstanceListFields():
495
  """gnt-instance list-fields"""
496
  qa_utils.GenericQueryFieldsTest("gnt-instance", query.INSTANCE_FIELDS.keys())
497

    
498

    
499
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
500
def TestInstanceConsole(instance):
501
  """gnt-instance console"""
502
  AssertCommand(["gnt-instance", "console", "--show-cmd", instance["name"]])
503

    
504

    
505
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
506
def TestReplaceDisks(instance, pnode, snode, othernode):
507
  """gnt-instance replace-disks"""
508
  # pylint: disable=W0613
509
  # due to unused pnode arg
510
  # FIXME: should be removed from the function completely
511
  def buildcmd(args):
512
    cmd = ["gnt-instance", "replace-disks"]
513
    cmd.extend(args)
514
    cmd.append(instance["name"])
515
    return cmd
516

    
517
  options = qa_config.get("options", {})
518
  use_ialloc = options.get("use-iallocators", True)
519
  for data in [
520
    ["-p"],
521
    ["-s"],
522
    # A placeholder; the actual command choice depends on use_ialloc
523
    None,
524
    # Restore the original secondary
525
    ["--new-secondary=%s" % snode["primary"]],
526
    ]:
527
    if data is None:
528
      if use_ialloc:
529
        data = ["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT]
530
      else:
531
        data = ["--new-secondary=%s" % othernode["primary"]]
532
    AssertCommand(buildcmd(data))
533

    
534
  AssertCommand(buildcmd(["-a"]))
535
  AssertCommand(["gnt-instance", "stop", instance["name"]])
536
  AssertCommand(buildcmd(["-a"]), fail=True)
537
  AssertCommand(["gnt-instance", "activate-disks", instance["name"]])
538
  AssertCommand(["gnt-instance", "activate-disks", "--wait-for-sync",
539
                 instance["name"]])
540
  AssertCommand(buildcmd(["-a"]))
541
  AssertCommand(["gnt-instance", "start", instance["name"]])
542

    
543

    
544
def _AssertRecreateDisks(cmdargs, instance, fail=False, check=True,
545
                         destroy=True):
546
  """Execute gnt-instance recreate-disks and check the result
547

548
  @param cmdargs: Arguments (instance name excluded)
549
  @param instance: Instance to operate on
550
  @param fail: True if the command is expected to fail
551
  @param check: If True and fail is False, check that the disks work
552
  @prama destroy: If True, destroy the old disks first
553

554
  """
555
  if destroy:
556
    _DestroyInstanceVolumes(instance)
557
  AssertCommand((["gnt-instance", "recreate-disks"] + cmdargs +
558
                 [instance["name"]]), fail)
559
  if not fail and check:
560
    # Quick check that the disks are there
561
    AssertCommand(["gnt-instance", "activate-disks", instance["name"]])
562
    AssertCommand(["gnt-instance", "activate-disks", "--wait-for-sync",
563
                   instance["name"]])
564
    AssertCommand(["gnt-instance", "deactivate-disks", instance["name"]])
565

    
566

    
567
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
568
def TestRecreateDisks(instance, pnode, snode, othernodes):
569
  """gnt-instance recreate-disks
570

571
  @param instance: Instance to work on
572
  @param pnode: Primary node
573
  @param snode: Secondary node, or None for sigle-homed instances
574
  @param othernodes: list/tuple of nodes where to temporarily recreate disks
575

576
  """
577
  options = qa_config.get("options", {})
578
  use_ialloc = options.get("use-iallocators", True)
579
  other_seq = ":".join([n["primary"] for n in othernodes])
580
  orig_seq = pnode["primary"]
581
  if snode:
582
    orig_seq = orig_seq + ":" + snode["primary"]
583
  # These fail because the instance is running
584
  _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
585
  if use_ialloc:
586
    _AssertRecreateDisks(["-I", "hail"], instance, fail=True, destroy=False)
587
  else:
588
    _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
589
  AssertCommand(["gnt-instance", "stop", instance["name"]])
590
  # Disks exist: this should fail
591
  _AssertRecreateDisks([], instance, fail=True, destroy=False)
592
  # Recreate disks in place
593
  _AssertRecreateDisks([], instance)
594
  # Move disks away
595
  if use_ialloc:
596
    _AssertRecreateDisks(["-I", "hail"], instance)
597
    # Move disks somewhere else
598
    _AssertRecreateDisks(["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT],
599
                         instance)
600
  else:
601
    _AssertRecreateDisks(["-n", other_seq], instance)
602
  # Move disks back
603
  _AssertRecreateDisks(["-n", orig_seq], instance, check=False)
604
  # This and InstanceCheck decoration check that the disks are working
605
  AssertCommand(["gnt-instance", "reinstall", "-f", instance["name"]])
606
  AssertCommand(["gnt-instance", "start", instance["name"]])
607

    
608

    
609
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
610
def TestInstanceExport(instance, node):
611
  """gnt-backup export -n ..."""
612
  name = instance["name"]
613
  AssertCommand(["gnt-backup", "export", "-n", node["primary"], name])
614
  return qa_utils.ResolveInstanceName(name)
615

    
616

    
617
@InstanceCheck(None, INST_DOWN, FIRST_ARG)
618
def TestInstanceExportWithRemove(instance, node):
619
  """gnt-backup export --remove-instance"""
620
  AssertCommand(["gnt-backup", "export", "-n", node["primary"],
621
                 "--remove-instance", instance["name"]])
622
  qa_config.ReleaseInstance(instance)
623

    
624

    
625
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
626
def TestInstanceExportNoTarget(instance):
627
  """gnt-backup export (without target node, should fail)"""
628
  AssertCommand(["gnt-backup", "export", instance["name"]], fail=True)
629

    
630

    
631
@InstanceCheck(None, INST_DOWN, FIRST_ARG)
632
def TestInstanceImport(newinst, node, expnode, name):
633
  """gnt-backup import"""
634
  cmd = (["gnt-backup", "import",
635
          "--disk-template=plain",
636
          "--no-ip-check",
637
          "--src-node=%s" % expnode["primary"],
638
          "--src-dir=%s/%s" % (pathutils.EXPORT_DIR, name),
639
          "--node=%s" % node["primary"]] +
640
         _GetGenericAddParameters(newinst, force_mac=constants.VALUE_GENERATE))
641
  cmd.append(newinst["name"])
642
  AssertCommand(cmd)
643

    
644

    
645
def TestBackupList(expnode):
646
  """gnt-backup list"""
647
  AssertCommand(["gnt-backup", "list", "--node=%s" % expnode["primary"]])
648

    
649
  qa_utils.GenericQueryTest("gnt-backup", query.EXPORT_FIELDS.keys(),
650
                            namefield=None, test_unknown=False)
651

    
652

    
653
def TestBackupListFields():
654
  """gnt-backup list-fields"""
655
  qa_utils.GenericQueryFieldsTest("gnt-backup", query.EXPORT_FIELDS.keys())