4 # Copyright (C) 2007, 2011, 2012, 2013 Google Inc.
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.
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.
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
22 """Instance related QA tests.
29 from ganeti import utils
30 from ganeti import constants
31 from ganeti import query
32 from ganeti import pathutils
38 from qa_utils import AssertIn, AssertCommand, AssertEqual
39 from qa_utils import InstanceCheck, INST_DOWN, INST_UP, FIRST_ARG, RETURN_VALUE
42 def _GetDiskStatePath(disk):
43 return "/sys/block/%s/device/state" % disk
46 def _GetGenericAddParameters(inst, force_mac=None):
48 params.append("%s=%s,%s=%s" % (constants.BE_MINMEM,
49 qa_config.get(constants.BE_MINMEM),
51 qa_config.get(constants.BE_MAXMEM)))
52 for idx, size in enumerate(qa_config.get("disk")):
53 params.extend(["--disk", "%s:size=%s" % (idx, size)])
55 # Set static MAC address if configured
59 nic0_mac = qa_config.GetInstanceNicMac(inst)
61 params.extend(["--net", "0:mac=%s" % nic0_mac])
66 def _DiskTest(node, disk_template):
67 instance = qa_config.AcquireInstance()
69 cmd = (["gnt-instance", "add",
70 "--os-type=%s" % qa_config.get("os"),
71 "--disk-template=%s" % disk_template,
73 _GetGenericAddParameters(instance))
74 cmd.append(instance["name"])
78 _CheckSsconfInstanceList(instance["name"])
79 qa_config.SetInstanceTemplate(instance, disk_template)
83 qa_config.ReleaseInstance(instance)
87 def _GetInstanceInfo(instance):
88 """Return information about the actual state of an instance.
90 @type instance: string
91 @param instance: the instance name
92 @return: a dictionary with two keys:
93 - "nodes": instance nodes, a list of strings
94 - "volumes": instance volume IDs, a list of strings
97 master = qa_config.GetMasterNode()
98 infocmd = utils.ShellQuoteArgs(["gnt-instance", "info", instance])
99 info_out = qa_utils.GetCommandOutput(master["primary"], infocmd)
100 re_node = re.compile(r"^\s+-\s+(?:primary|secondaries):\s+(\S.+)$")
101 node_elem = r"([^,()]+)(?:\s+\([^)]+\))?"
102 # re_nodelist matches a list of nodes returned by gnt-instance info, e.g.:
104 # node2.fqdn,node3.fqdn
105 # node4.fqdn (group mygroup, group UUID 01234567-abcd-0123-4567-0123456789ab)
106 # FIXME This works with no more than 2 secondaries
107 re_nodelist = re.compile(node_elem + "(?:," + node_elem + ")?$")
108 re_vol = re.compile(r"^\s+logical_id:\s+(\S+)$")
111 for line in info_out.splitlines():
112 m = re_node.match(line)
115 m2 = re_nodelist.match(nodestr)
117 nodes.extend(filter(None, m2.groups()))
119 nodes.append(nodestr)
120 m = re_vol.match(line)
122 vols.append(m.group(1))
125 return {"nodes": nodes, "volumes": vols}
128 def _DestroyInstanceVolumes(instance):
129 """Remove all the LVM volumes of an instance.
131 This is used to simulate HW errors (dead nodes, broken disks...); the
132 configuration of the instance is not affected.
133 @type instance: dictionary
134 @param instance: the instance
137 info = _GetInstanceInfo(instance["name"])
138 vols = info["volumes"]
139 for node in info["nodes"]:
140 AssertCommand(["lvremove", "-f"] + vols, node=node)
143 def _GetBoolInstanceField(instance, field):
144 """Get the Boolean value of a field of an instance.
146 @type instance: string
147 @param instance: Instance name
149 @param field: Name of the field
152 master = qa_config.GetMasterNode()
153 infocmd = utils.ShellQuoteArgs(["gnt-instance", "list", "--no-headers",
154 "-o", field, instance])
155 info_out = qa_utils.GetCommandOutput(master["primary"], infocmd).strip()
158 elif info_out == "N":
161 raise qa_error.Error("Field %s of instance %s has a non-Boolean value:"
162 " %s" % (field, instance, info_out))
165 def IsFailoverSupported(instance):
166 templ = qa_config.GetInstanceTemplate(instance)
167 return templ in constants.DTS_MIRRORED
170 def IsMigrationSupported(instance):
171 templ = qa_config.GetInstanceTemplate(instance)
172 return templ in constants.DTS_MIRRORED
175 def IsDiskReplacingSupported(instance):
176 templ = qa_config.GetInstanceTemplate(instance)
177 return templ == constants.DT_DRBD8
180 @InstanceCheck(None, INST_UP, RETURN_VALUE)
181 def TestInstanceAddWithPlainDisk(nodes):
182 """gnt-instance add -t plain"""
183 assert len(nodes) == 1
184 return _DiskTest(nodes[0]["primary"], "plain")
187 @InstanceCheck(None, INST_UP, RETURN_VALUE)
188 def TestInstanceAddWithDrbdDisk(nodes):
189 """gnt-instance add -t drbd"""
190 assert len(nodes) == 2
191 return _DiskTest(":".join(map(operator.itemgetter("primary"), nodes)),
195 @InstanceCheck(None, INST_DOWN, FIRST_ARG)
196 def TestInstanceRemove(instance):
197 """gnt-instance remove"""
198 AssertCommand(["gnt-instance", "remove", "-f", instance["name"]])
200 qa_config.ReleaseInstance(instance)
203 @InstanceCheck(INST_DOWN, INST_UP, FIRST_ARG)
204 def TestInstanceStartup(instance):
205 """gnt-instance startup"""
206 AssertCommand(["gnt-instance", "startup", instance["name"]])
209 @InstanceCheck(INST_UP, INST_DOWN, FIRST_ARG)
210 def TestInstanceShutdown(instance):
211 """gnt-instance shutdown"""
212 AssertCommand(["gnt-instance", "shutdown", instance["name"]])
215 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
216 def TestInstanceReboot(instance):
217 """gnt-instance reboot"""
218 options = qa_config.get("options", {})
219 reboot_types = options.get("reboot-types", constants.REBOOT_TYPES)
220 name = instance["name"]
221 for rtype in reboot_types:
222 AssertCommand(["gnt-instance", "reboot", "--type=%s" % rtype, name])
224 AssertCommand(["gnt-instance", "shutdown", name])
225 qa_utils.RunInstanceCheck(instance, False)
226 AssertCommand(["gnt-instance", "reboot", name])
228 master = qa_config.GetMasterNode()
229 cmd = ["gnt-instance", "list", "--no-headers", "-o", "status", name]
230 result_output = qa_utils.GetCommandOutput(master["primary"],
231 utils.ShellQuoteArgs(cmd))
232 AssertEqual(result_output.strip(), constants.INSTST_RUNNING)
235 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
236 def TestInstanceReinstall(instance):
237 """gnt-instance reinstall"""
238 AssertCommand(["gnt-instance", "reinstall", "-f", instance["name"]])
240 # Test with non-existant OS definition
241 AssertCommand(["gnt-instance", "reinstall", "-f",
242 "--os-type=NonExistantOsForQa",
247 def _ReadSsconfInstanceList():
248 """Reads ssconf_instance_list from the master node.
251 master = qa_config.GetMasterNode()
253 cmd = ["cat", utils.PathJoin(pathutils.DATA_DIR,
254 "ssconf_%s" % constants.SS_INSTANCE_LIST)]
256 return qa_utils.GetCommandOutput(master["primary"],
257 utils.ShellQuoteArgs(cmd)).splitlines()
260 def _CheckSsconfInstanceList(instance):
261 """Checks if a certain instance is in the ssconf instance list.
263 @type instance: string
264 @param instance: Instance name
267 AssertIn(qa_utils.ResolveInstanceName(instance),
268 _ReadSsconfInstanceList())
271 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
272 def TestInstanceRenameAndBack(rename_source, rename_target):
273 """gnt-instance rename
275 This must leave the instance with the original name, not the target
279 _CheckSsconfInstanceList(rename_source)
281 # first do a rename to a different actual name, expecting it to fail
282 qa_utils.AddToEtcHosts(["meeeeh-not-exists", rename_target])
284 AssertCommand(["gnt-instance", "rename", rename_source, rename_target],
286 _CheckSsconfInstanceList(rename_source)
288 qa_utils.RemoveFromEtcHosts(["meeeeh-not-exists", rename_target])
290 # Check instance volume tags correctly updated
291 # FIXME: this is LVM specific!
292 info = _GetInstanceInfo(rename_source)
293 tags_cmd = ("lvs -o tags --noheadings %s | grep " %
294 (" ".join(info["volumes"]), ))
296 # and now rename instance to rename_target...
297 AssertCommand(["gnt-instance", "rename", rename_source, rename_target])
298 _CheckSsconfInstanceList(rename_target)
299 qa_utils.RunInstanceCheck(rename_source, False)
300 qa_utils.RunInstanceCheck(rename_target, False)
302 # NOTE: tags might not be the exactly as the instance name, due to
303 # charset restrictions; hence the test might be flaky
304 if rename_source != rename_target:
305 for node in info["nodes"]:
306 AssertCommand(tags_cmd + rename_source, node=node, fail=True)
307 AssertCommand(tags_cmd + rename_target, node=node, fail=False)
310 AssertCommand(["gnt-instance", "rename", rename_target, rename_source])
311 _CheckSsconfInstanceList(rename_source)
312 qa_utils.RunInstanceCheck(rename_target, False)
314 if rename_source != rename_target:
315 for node in info["nodes"]:
316 AssertCommand(tags_cmd + rename_source, node=node, fail=False)
317 AssertCommand(tags_cmd + rename_target, node=node, fail=True)
320 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
321 def TestInstanceFailover(instance):
322 """gnt-instance failover"""
323 if not IsFailoverSupported(instance):
324 print qa_utils.FormatInfo("Instance doesn't support failover, skipping"
328 cmd = ["gnt-instance", "failover", "--force", instance["name"]]
332 qa_utils.RunInstanceCheck(instance, True)
338 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
339 def TestInstanceMigrate(instance, toggle_always_failover=True):
340 """gnt-instance migrate"""
341 if not IsMigrationSupported(instance):
342 print qa_utils.FormatInfo("Instance doesn't support migration, skipping"
346 cmd = ["gnt-instance", "migrate", "--force", instance["name"]]
347 af_par = constants.BE_ALWAYS_FAILOVER
348 af_field = "be/" + constants.BE_ALWAYS_FAILOVER
349 af_init_val = _GetBoolInstanceField(instance["name"], af_field)
353 # TODO: Verify the choice between failover and migration
354 qa_utils.RunInstanceCheck(instance, True)
356 # ... and back (possibly with always_failover toggled)
357 if toggle_always_failover:
358 AssertCommand(["gnt-instance", "modify", "-B",
359 ("%s=%s" % (af_par, not af_init_val)),
362 # TODO: Verify the choice between failover and migration
363 qa_utils.RunInstanceCheck(instance, True)
364 if toggle_always_failover:
365 AssertCommand(["gnt-instance", "modify", "-B",
366 ("%s=%s" % (af_par, af_init_val)), instance["name"]])
368 # TODO: Split into multiple tests
369 AssertCommand(["gnt-instance", "shutdown", instance["name"]])
370 qa_utils.RunInstanceCheck(instance, False)
371 AssertCommand(cmd, fail=True)
372 AssertCommand(["gnt-instance", "migrate", "--force", "--allow-failover",
374 AssertCommand(["gnt-instance", "start", instance["name"]])
376 # @InstanceCheck enforces the check that the instance is running
377 qa_utils.RunInstanceCheck(instance, True)
379 AssertCommand(["gnt-instance", "modify", "-B",
381 (constants.BE_ALWAYS_FAILOVER, constants.VALUE_TRUE)),
385 qa_utils.RunInstanceCheck(instance, True)
386 # TODO: Verify that a failover has been done instead of a migration
388 # TODO: Verify whether the default value is restored here (not hardcoded)
389 AssertCommand(["gnt-instance", "modify", "-B",
391 (constants.BE_ALWAYS_FAILOVER, constants.VALUE_FALSE)),
395 qa_utils.RunInstanceCheck(instance, True)
398 def TestInstanceInfo(instance):
399 """gnt-instance info"""
400 AssertCommand(["gnt-instance", "info", instance["name"]])
403 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
404 def TestInstanceModify(instance):
405 """gnt-instance modify"""
406 default_hv = qa_config.GetDefaultHypervisor()
408 # Assume /sbin/init exists on all systems
409 test_kernel = "/sbin/init"
410 test_initrd = test_kernel
412 orig_maxmem = qa_config.get(constants.BE_MAXMEM)
413 orig_minmem = qa_config.get(constants.BE_MINMEM)
414 #orig_bridge = qa_config.get("bridge", "xen-br0")
417 ["-B", "%s=128" % constants.BE_MINMEM],
418 ["-B", "%s=128" % constants.BE_MAXMEM],
419 ["-B", "%s=%s,%s=%s" % (constants.BE_MINMEM, orig_minmem,
420 constants.BE_MAXMEM, orig_maxmem)],
421 ["-B", "%s=2" % constants.BE_VCPUS],
422 ["-B", "%s=1" % constants.BE_VCPUS],
423 ["-B", "%s=%s" % (constants.BE_VCPUS, constants.VALUE_DEFAULT)],
424 ["-B", "%s=%s" % (constants.BE_ALWAYS_FAILOVER, constants.VALUE_TRUE)],
425 ["-B", "%s=%s" % (constants.BE_ALWAYS_FAILOVER, constants.VALUE_DEFAULT)],
427 ["-H", "%s=%s" % (constants.HV_KERNEL_PATH, test_kernel)],
428 ["-H", "%s=%s" % (constants.HV_KERNEL_PATH, constants.VALUE_DEFAULT)],
431 #["--bridge", "xen-br1"],
432 #["--bridge", orig_bridge],
435 if default_hv == constants.HT_XEN_PVM:
437 ["-H", "%s=%s" % (constants.HV_INITRD_PATH, test_initrd)],
438 ["-H", "no_%s" % (constants.HV_INITRD_PATH, )],
439 ["-H", "%s=%s" % (constants.HV_INITRD_PATH, constants.VALUE_DEFAULT)],
441 elif default_hv == constants.HT_XEN_HVM:
443 ["-H", "%s=acn" % constants.HV_BOOT_ORDER],
444 ["-H", "%s=%s" % (constants.HV_BOOT_ORDER, constants.VALUE_DEFAULT)],
448 AssertCommand(["gnt-instance", "modify"] + alist + [instance["name"]])
451 AssertCommand(["gnt-instance", "modify", instance["name"]], fail=True)
453 # Marking offline while instance is running must fail...
454 AssertCommand(["gnt-instance", "modify", "--offline", instance["name"]],
457 # ...while making it online is ok, and should work
458 AssertCommand(["gnt-instance", "modify", "--online", instance["name"]])
461 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
462 def TestInstanceStoppedModify(instance):
463 """gnt-instance modify (stopped instance)"""
464 name = instance["name"]
466 # Instance was not marked offline; try marking it online once more
467 AssertCommand(["gnt-instance", "modify", "--online", name])
469 # Mark instance as offline
470 AssertCommand(["gnt-instance", "modify", "--offline", name])
472 # When the instance is offline shutdown should only work with --force,
473 # while start should never work
474 AssertCommand(["gnt-instance", "shutdown", name], fail=True)
475 AssertCommand(["gnt-instance", "shutdown", "--force", name])
476 AssertCommand(["gnt-instance", "start", name], fail=True)
477 AssertCommand(["gnt-instance", "start", "--force", name], fail=True)
479 # Also do offline to offline
480 AssertCommand(["gnt-instance", "modify", "--offline", name])
483 AssertCommand(["gnt-instance", "modify", "--online", name])
486 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
487 def TestInstanceConvertDiskToPlain(instance, inodes):
488 """gnt-instance modify -t"""
489 name = instance["name"]
490 template = qa_config.GetInstanceTemplate(instance)
491 if template != "drbd":
492 print qa_utils.FormatInfo("Unsupported template %s, skipping conversion"
495 assert len(inodes) == 2
496 AssertCommand(["gnt-instance", "modify", "-t", "plain", name])
497 AssertCommand(["gnt-instance", "modify", "-t", "drbd",
498 "-n", inodes[1]["primary"], name])
501 @InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG)
502 def TestInstanceGrowDisk(instance):
503 """gnt-instance grow-disk"""
504 if qa_config.GetExclusiveStorage():
505 print qa_utils.FormatInfo("Test not supported with exclusive_storage")
507 name = instance["name"]
508 all_size = qa_config.get("disk")
509 all_grow = qa_config.get("disk-growth")
511 # missing disk sizes but instance grow disk has been enabled,
512 # let's set fixed/nomimal growth
513 all_grow = ["128M" for _ in all_size]
514 for idx, (size, grow) in enumerate(zip(all_size, all_grow)):
515 # succeed in grow by amount
516 AssertCommand(["gnt-instance", "grow-disk", name, str(idx), grow])
517 # fail in grow to the old size
518 AssertCommand(["gnt-instance", "grow-disk", "--absolute", name, str(idx),
520 # succeed to grow to old size + 2 * growth
521 int_size = utils.ParseUnit(size)
522 int_grow = utils.ParseUnit(grow)
523 AssertCommand(["gnt-instance", "grow-disk", "--absolute", name, str(idx),
524 str(int_size + 2 * int_grow)])
527 def TestInstanceList():
528 """gnt-instance list"""
529 qa_utils.GenericQueryTest("gnt-instance", query.INSTANCE_FIELDS.keys())
532 def TestInstanceListFields():
533 """gnt-instance list-fields"""
534 qa_utils.GenericQueryFieldsTest("gnt-instance", query.INSTANCE_FIELDS.keys())
537 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
538 def TestInstanceConsole(instance):
539 """gnt-instance console"""
540 AssertCommand(["gnt-instance", "console", "--show-cmd", instance["name"]])
543 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
544 def TestReplaceDisks(instance, curr_nodes, other_nodes):
545 """gnt-instance replace-disks"""
547 cmd = ["gnt-instance", "replace-disks"]
549 cmd.append(instance["name"])
552 if not IsDiskReplacingSupported(instance):
553 print qa_utils.FormatInfo("Instance doesn't support disk replacing,"
557 # Currently all supported templates have one primary and one secondary node
558 assert len(curr_nodes) == 2
559 snode = curr_nodes[1]
560 assert len(other_nodes) == 1
561 othernode = other_nodes[0]
563 options = qa_config.get("options", {})
564 use_ialloc = options.get("use-iallocators", True)
568 # A placeholder; the actual command choice depends on use_ialloc
570 # Restore the original secondary
571 ["--new-secondary=%s" % snode["primary"]],
575 data = ["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT]
577 data = ["--new-secondary=%s" % othernode["primary"]]
578 AssertCommand(buildcmd(data))
580 AssertCommand(buildcmd(["-a"]))
581 AssertCommand(["gnt-instance", "stop", instance["name"]])
582 AssertCommand(buildcmd(["-a"]), fail=True)
583 AssertCommand(["gnt-instance", "activate-disks", instance["name"]])
584 AssertCommand(["gnt-instance", "activate-disks", "--wait-for-sync",
586 AssertCommand(buildcmd(["-a"]))
587 AssertCommand(["gnt-instance", "start", instance["name"]])
590 def _AssertRecreateDisks(cmdargs, instance, fail=False, check=True,
592 """Execute gnt-instance recreate-disks and check the result
594 @param cmdargs: Arguments (instance name excluded)
595 @param instance: Instance to operate on
596 @param fail: True if the command is expected to fail
597 @param check: If True and fail is False, check that the disks work
598 @prama destroy: If True, destroy the old disks first
602 _DestroyInstanceVolumes(instance)
603 AssertCommand((["gnt-instance", "recreate-disks"] + cmdargs +
604 [instance["name"]]), fail)
605 if not fail and check:
606 # Quick check that the disks are there
607 AssertCommand(["gnt-instance", "activate-disks", instance["name"]])
608 AssertCommand(["gnt-instance", "activate-disks", "--wait-for-sync",
610 AssertCommand(["gnt-instance", "deactivate-disks", instance["name"]])
613 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
614 def TestRecreateDisks(instance, inodes, othernodes):
615 """gnt-instance recreate-disks
617 @param instance: Instance to work on
618 @param inodes: List of the current nodes of the instance
619 @param othernodes: list/tuple of nodes where to temporarily recreate disks
622 options = qa_config.get("options", {})
623 use_ialloc = options.get("use-iallocators", True)
624 other_seq = ":".join([n["primary"] for n in othernodes])
625 orig_seq = ":".join([n["primary"] for n in inodes])
626 # These fail because the instance is running
627 _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
629 _AssertRecreateDisks(["-I", "hail"], instance, fail=True, destroy=False)
631 _AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False)
632 AssertCommand(["gnt-instance", "stop", instance["name"]])
633 # Disks exist: this should fail
634 _AssertRecreateDisks([], instance, fail=True, destroy=False)
635 # Recreate disks in place
636 _AssertRecreateDisks([], instance)
639 _AssertRecreateDisks(["-I", "hail"], instance)
640 # Move disks somewhere else
641 _AssertRecreateDisks(["-I", constants.DEFAULT_IALLOCATOR_SHORTCUT],
644 _AssertRecreateDisks(["-n", other_seq], instance)
646 _AssertRecreateDisks(["-n", orig_seq], instance, check=False)
647 # This and InstanceCheck decoration check that the disks are working
648 AssertCommand(["gnt-instance", "reinstall", "-f", instance["name"]])
649 AssertCommand(["gnt-instance", "start", instance["name"]])
652 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
653 def TestInstanceExport(instance, node):
654 """gnt-backup export -n ..."""
655 name = instance["name"]
656 AssertCommand(["gnt-backup", "export", "-n", node["primary"], name])
657 return qa_utils.ResolveInstanceName(name)
660 @InstanceCheck(None, INST_DOWN, FIRST_ARG)
661 def TestInstanceExportWithRemove(instance, node):
662 """gnt-backup export --remove-instance"""
663 AssertCommand(["gnt-backup", "export", "-n", node["primary"],
664 "--remove-instance", instance["name"]])
665 qa_config.ReleaseInstance(instance)
668 @InstanceCheck(INST_UP, INST_UP, FIRST_ARG)
669 def TestInstanceExportNoTarget(instance):
670 """gnt-backup export (without target node, should fail)"""
671 AssertCommand(["gnt-backup", "export", instance["name"]], fail=True)
674 @InstanceCheck(None, INST_DOWN, FIRST_ARG)
675 def TestInstanceImport(newinst, node, expnode, name):
676 """gnt-backup import"""
677 templ = constants.DT_PLAIN
678 cmd = (["gnt-backup", "import",
679 "--disk-template=%s" % templ,
681 "--src-node=%s" % expnode["primary"],
682 "--src-dir=%s/%s" % (pathutils.EXPORT_DIR, name),
683 "--node=%s" % node["primary"]] +
684 _GetGenericAddParameters(newinst, force_mac=constants.VALUE_GENERATE))
685 cmd.append(newinst["name"])
687 qa_config.SetInstanceTemplate(newinst, templ)
690 def TestBackupList(expnode):
691 """gnt-backup list"""
692 AssertCommand(["gnt-backup", "list", "--node=%s" % expnode["primary"]])
694 qa_utils.GenericQueryTest("gnt-backup", query.EXPORT_FIELDS.keys(),
695 namefield=None, test_unknown=False)
698 def TestBackupListFields():
699 """gnt-backup list-fields"""
700 qa_utils.GenericQueryFieldsTest("gnt-backup", query.EXPORT_FIELDS.keys())