Revision c99200a3
b/qa/ganeti-qa.py | ||
---|---|---|
340 | 340 |
qa_group.GetDefaultGroup()) |
341 | 341 |
|
342 | 342 |
|
343 |
def RunExportImportTests(instance, pnode, snode):
|
|
343 |
def RunExportImportTests(instance, inodes):
|
|
344 | 344 |
"""Tries to export and import the instance. |
345 | 345 |
|
346 |
@param pnode: current primary node of the instance |
|
347 |
@param snode: current secondary node of the instance, if any, |
|
348 |
otherwise None |
|
346 |
@type inodes: list of nodes |
|
347 |
@param inodes: current nodes of the instance |
|
349 | 348 |
|
350 | 349 |
""" |
351 | 350 |
if qa_config.TestEnabled("instance-export"): |
352 | 351 |
RunTest(qa_instance.TestInstanceExportNoTarget, instance) |
353 | 352 |
|
353 |
pnode = inodes[0] |
|
354 | 354 |
expnode = qa_config.AcquireNode(exclude=pnode) |
355 | 355 |
try: |
356 | 356 |
name = RunTest(qa_instance.TestInstanceExport, instance, expnode) |
... | ... | |
373 | 373 |
if qa_config.TestEnabled(["rapi", "inter-cluster-instance-move"]): |
374 | 374 |
newinst = qa_config.AcquireInstance() |
375 | 375 |
try: |
376 |
if snode is None: |
|
377 |
excl = [pnode] |
|
378 |
else: |
|
379 |
excl = [pnode, snode] |
|
380 |
tnode = qa_config.AcquireNode(exclude=excl) |
|
376 |
tnode = qa_config.AcquireNode(exclude=inodes) |
|
381 | 377 |
try: |
382 | 378 |
RunTest(qa_rapi.TestInterClusterInstanceMove, instance, newinst, |
383 |
pnode, snode, tnode)
|
|
379 |
inodes, tnode)
|
|
384 | 380 |
finally: |
385 | 381 |
qa_config.ReleaseNode(tnode) |
386 | 382 |
finally: |
... | ... | |
414 | 410 |
qa_config.ReleaseNode(othernode) |
415 | 411 |
|
416 | 412 |
|
417 |
def RunHardwareFailureTests(instance, pnode, snode):
|
|
413 |
def RunHardwareFailureTests(instance, inodes):
|
|
418 | 414 |
"""Test cluster internal hardware failure recovery. |
419 | 415 |
|
420 | 416 |
""" |
... | ... | |
427 | 423 |
qa_rapi.TestRapiInstanceMigrate, instance) |
428 | 424 |
|
429 | 425 |
if qa_config.TestEnabled("instance-replace-disks"): |
430 |
othernode = qa_config.AcquireNode(exclude=[pnode, snode]) |
|
426 |
# We just need alternative secondary nodes, hence "- 1" |
|
427 |
othernodes = qa_config.AcquireManyNodes(len(inodes) - 1, exclude=inodes) |
|
431 | 428 |
try: |
432 | 429 |
RunTestIf("rapi", qa_rapi.TestRapiInstanceReplaceDisks, instance) |
433 | 430 |
RunTest(qa_instance.TestReplaceDisks, |
434 |
instance, pnode, snode, othernode)
|
|
431 |
instance, inodes, othernodes)
|
|
435 | 432 |
finally: |
436 |
qa_config.ReleaseNode(othernode) |
|
433 |
qa_config.ReleaseManyNodes(othernodes) |
|
434 |
del othernodes |
|
437 | 435 |
|
438 | 436 |
if qa_config.TestEnabled("instance-recreate-disks"): |
439 |
othernode1 = qa_config.AcquireNode(exclude=[pnode, snode]) |
|
440 | 437 |
try: |
441 |
othernode2 = qa_config.AcquireNode(exclude=[pnode, snode, othernode1]) |
|
438 |
acquirednodes = qa_config.AcquireManyNodes(len(inodes), exclude=inodes) |
|
439 |
othernodes = acquirednodes |
|
442 | 440 |
except qa_error.OutOfNodesError: |
443 |
# Let's reuse one of the nodes if the cluster is not big enough |
|
444 |
othernode2 = pnode |
|
441 |
if len(inodes) > 1: |
|
442 |
# If the cluster is not big enough, let's reuse some of the nodes, but |
|
443 |
# with different roles. In this way, we can test a DRBD instance even on |
|
444 |
# a 3-node cluster. |
|
445 |
acquirednodes = [qa_config.AcquireNode(exclude=inodes)] |
|
446 |
othernodes = acquirednodes + inodes[:-1] |
|
447 |
else: |
|
448 |
raise |
|
445 | 449 |
try: |
446 | 450 |
RunTest(qa_instance.TestRecreateDisks, |
447 |
instance, pnode, snode, [othernode1, othernode2])
|
|
451 |
instance, inodes, othernodes)
|
|
448 | 452 |
finally: |
449 |
qa_config.ReleaseNode(othernode1) |
|
450 |
if othernode2 != pnode: |
|
451 |
qa_config.ReleaseNode(othernode2) |
|
452 |
|
|
453 |
RunTestIf("node-evacuate", qa_node.TestNodeEvacuate, pnode, snode) |
|
453 |
qa_config.ReleaseManyNodes(acquirednodes) |
|
454 | 454 |
|
455 |
RunTestIf("node-failover", qa_node.TestNodeFailover, pnode, snode) |
|
455 |
if len(inodes) >= 2: |
|
456 |
RunTestIf("node-evacuate", qa_node.TestNodeEvacuate, inodes[0], inodes[1]) |
|
457 |
RunTestIf("node-failover", qa_node.TestNodeFailover, inodes[0], inodes[1]) |
|
456 | 458 |
|
457 | 459 |
|
458 | 460 |
def RunExclusiveStorageTests(): |
... | ... | |
471 | 473 |
if qa_config.TestEnabled("instance-add-plain-disk"): |
472 | 474 |
# Make sure that the cluster doesn't have any pre-existing problem |
473 | 475 |
qa_cluster.AssertClusterVerify() |
474 |
instance1 = qa_instance.TestInstanceAddWithPlainDisk(node)
|
|
475 |
instance2 = qa_instance.TestInstanceAddWithPlainDisk(node)
|
|
476 |
instance1 = qa_instance.TestInstanceAddWithPlainDisk([node])
|
|
477 |
instance2 = qa_instance.TestInstanceAddWithPlainDisk([node])
|
|
476 | 478 |
# cluster-verify checks that disks are allocated correctly |
477 | 479 |
qa_cluster.AssertClusterVerify() |
478 | 480 |
qa_instance.TestInstanceRemove(instance1) |
... | ... | |
481 | 483 |
snode = qa_config.AcquireNode() |
482 | 484 |
try: |
483 | 485 |
qa_cluster.TestSetExclStorCluster(False) |
484 |
instance = qa_instance.TestInstanceAddWithDrbdDisk(node, snode)
|
|
486 |
instance = qa_instance.TestInstanceAddWithDrbdDisk([node, snode])
|
|
485 | 487 |
qa_cluster.TestSetExclStorCluster(True) |
486 | 488 |
exp_err = [constants.CV_EINSTANCEUNSUITABLENODE] |
487 | 489 |
qa_cluster.AssertClusterVerify(fail=True, errors=exp_err) |
... | ... | |
542 | 544 |
del rapi_instance |
543 | 545 |
|
544 | 546 |
if qa_config.TestEnabled("instance-add-plain-disk"): |
545 |
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
|
|
547 |
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, [pnode])
|
|
546 | 548 |
RunCommonInstanceTests(instance) |
547 | 549 |
RunGroupListTests() |
548 | 550 |
RunTestIf("cluster-epo", qa_cluster.TestClusterEpo) |
549 |
RunExportImportTests(instance, pnode, None)
|
|
551 |
RunExportImportTests(instance, [pnode])
|
|
550 | 552 |
RunDaemonTests(instance) |
551 | 553 |
RunRepairDiskSizes() |
552 | 554 |
RunSingleHomedHardwareFailureTests(instance, pnode) |
... | ... | |
562 | 564 |
if qa_config.TestEnabled(name): |
563 | 565 |
snode = qa_config.AcquireNode(exclude=pnode) |
564 | 566 |
try: |
565 |
instance = RunTest(func, pnode, snode)
|
|
567 |
instance = RunTest(func, [pnode, snode])
|
|
566 | 568 |
RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, pnode) |
567 | 569 |
RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, snode) |
568 | 570 |
RunCommonInstanceTests(instance) |
... | ... | |
572 | 574 |
pnode["primary"], snode["primary"]) |
573 | 575 |
if qa_config.TestEnabled("instance-convert-disk"): |
574 | 576 |
RunTest(qa_instance.TestInstanceShutdown, instance) |
575 |
RunTest(qa_instance.TestInstanceConvertDisk, instance, snode) |
|
577 |
RunTest(qa_instance.TestInstanceConvertDiskToPlain, instance, |
|
578 |
[pnode, snode]) |
|
576 | 579 |
RunTest(qa_instance.TestInstanceStartup, instance) |
577 |
RunExportImportTests(instance, pnode, snode)
|
|
578 |
RunHardwareFailureTests(instance, pnode, snode)
|
|
580 |
RunExportImportTests(instance, [pnode, snode])
|
|
581 |
RunHardwareFailureTests(instance, [pnode, snode])
|
|
579 | 582 |
RunRepairDiskSizes() |
580 | 583 |
RunTest(qa_instance.TestInstanceRemove, instance) |
581 | 584 |
del instance |
... | ... | |
592 | 595 |
try: |
593 | 596 |
pnode = qa_config.AcquireNode(exclude=snode) |
594 | 597 |
try: |
595 |
instance = qa_instance.TestInstanceAddWithDrbdDisk(pnode, snode)
|
|
598 |
instance = qa_instance.TestInstanceAddWithDrbdDisk([pnode, snode])
|
|
596 | 599 |
qa_node.MakeNodeOffline(snode, "yes") |
597 | 600 |
try: |
598 | 601 |
RunTest(qa_instance.TestInstanceRemove, instance) |
... | ... | |
607 | 610 |
try: |
608 | 611 |
if qa_config.TestEnabled(["instance-add-plain-disk", "instance-export"]): |
609 | 612 |
for shutdown in [False, True]: |
610 |
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
|
|
613 |
instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, [pnode])
|
|
611 | 614 |
expnode = qa_config.AcquireNode(exclude=pnode) |
612 | 615 |
try: |
613 | 616 |
if shutdown: |
b/qa/qa_instance.py | ||
---|---|---|
23 | 23 |
|
24 | 24 |
""" |
25 | 25 |
|
26 |
import operator |
|
26 | 27 |
import re |
27 | 28 |
|
28 | 29 |
from ganeti import utils |
... | ... | |
177 | 178 |
|
178 | 179 |
|
179 | 180 |
@InstanceCheck(None, INST_UP, RETURN_VALUE) |
180 |
def TestInstanceAddWithPlainDisk(node): |
|
181 |
def TestInstanceAddWithPlainDisk(nodes):
|
|
181 | 182 |
"""gnt-instance add -t plain""" |
182 |
return _DiskTest(node["primary"], "plain") |
|
183 |
assert len(nodes) == 1 |
|
184 |
return _DiskTest(nodes[0]["primary"], "plain") |
|
183 | 185 |
|
184 | 186 |
|
185 | 187 |
@InstanceCheck(None, INST_UP, RETURN_VALUE) |
186 |
def TestInstanceAddWithDrbdDisk(node, node2):
|
|
188 |
def TestInstanceAddWithDrbdDisk(nodes):
|
|
187 | 189 |
"""gnt-instance add -t drbd""" |
188 |
return _DiskTest("%s:%s" % (node["primary"], node2["primary"]), |
|
190 |
assert len(nodes) == 2 |
|
191 |
return _DiskTest(":".join(map(operator.itemgetter("primary"), nodes)), |
|
189 | 192 |
"drbd") |
190 | 193 |
|
191 | 194 |
|
... | ... | |
481 | 484 |
|
482 | 485 |
|
483 | 486 |
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG) |
484 |
def TestInstanceConvertDisk(instance, snode):
|
|
487 |
def TestInstanceConvertDiskToPlain(instance, inodes):
|
|
485 | 488 |
"""gnt-instance modify -t""" |
486 | 489 |
name = instance["name"] |
487 | 490 |
template = qa_config.GetInstanceTemplate(instance) |
... | ... | |
489 | 492 |
print qa_utils.FormatInfo("Unsupported template %s, skipping conversion" |
490 | 493 |
" test" % template) |
491 | 494 |
return |
495 |
assert len(inodes) == 2 |
|
492 | 496 |
AssertCommand(["gnt-instance", "modify", "-t", "plain", name]) |
493 | 497 |
AssertCommand(["gnt-instance", "modify", "-t", "drbd", |
494 |
"-n", snode["primary"], name])
|
|
498 |
"-n", inodes[1]["primary"], name])
|
|
495 | 499 |
|
496 | 500 |
|
497 | 501 |
@InstanceCheck(INST_DOWN, INST_DOWN, FIRST_ARG) |
... | ... | |
537 | 541 |
|
538 | 542 |
|
539 | 543 |
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG) |
540 |
def TestReplaceDisks(instance, pnode, snode, othernode):
|
|
544 |
def TestReplaceDisks(instance, curr_nodes, other_nodes):
|
|
541 | 545 |
"""gnt-instance replace-disks""" |
542 |
# pylint: disable=W0613 |
|
543 |
# due to unused pnode arg |
|
544 |
# FIXME: should be removed from the function completely |
|
545 | 546 |
def buildcmd(args): |
546 | 547 |
cmd = ["gnt-instance", "replace-disks"] |
547 | 548 |
cmd.extend(args) |
... | ... | |
553 | 554 |
" skipping test") |
554 | 555 |
return |
555 | 556 |
|
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] |
|
562 |
|
|
556 | 563 |
options = qa_config.get("options", {}) |
557 | 564 |
use_ialloc = options.get("use-iallocators", True) |
558 | 565 |
for data in [ |
... | ... | |
604 | 611 |
|
605 | 612 |
|
606 | 613 |
@InstanceCheck(INST_UP, INST_UP, FIRST_ARG) |
607 |
def TestRecreateDisks(instance, pnode, snode, othernodes):
|
|
614 |
def TestRecreateDisks(instance, inodes, othernodes):
|
|
608 | 615 |
"""gnt-instance recreate-disks |
609 | 616 |
|
610 | 617 |
@param instance: Instance to work on |
611 |
@param pnode: Primary node |
|
612 |
@param snode: Secondary node, or None for sigle-homed instances |
|
618 |
@param inodes: List of the current nodes of the instance |
|
613 | 619 |
@param othernodes: list/tuple of nodes where to temporarily recreate disks |
614 | 620 |
|
615 | 621 |
""" |
616 | 622 |
options = qa_config.get("options", {}) |
617 | 623 |
use_ialloc = options.get("use-iallocators", True) |
618 | 624 |
other_seq = ":".join([n["primary"] for n in othernodes]) |
619 |
orig_seq = pnode["primary"] |
|
620 |
if snode: |
|
621 |
orig_seq = orig_seq + ":" + snode["primary"] |
|
625 |
orig_seq = ":".join([n["primary"] for n in inodes]) |
|
622 | 626 |
# These fail because the instance is running |
623 | 627 |
_AssertRecreateDisks(["-n", other_seq], instance, fail=True, destroy=False) |
624 | 628 |
if use_ialloc: |
b/qa/qa_rapi.py | ||
---|---|---|
759 | 759 |
|
760 | 760 |
|
761 | 761 |
def TestInterClusterInstanceMove(src_instance, dest_instance, |
762 |
pnode, snode, tnode):
|
|
762 |
inodes, tnode):
|
|
763 | 763 |
"""Test tools/move-instance""" |
764 | 764 |
master = qa_config.GetMasterNode() |
765 | 765 |
|
... | ... | |
772 | 772 |
|
773 | 773 |
# TODO: Run some instance tests before moving back |
774 | 774 |
|
775 |
if snode is None: |
|
775 |
if len(inodes) > 1: |
|
776 |
# No disk template currently requires more than 1 secondary node. If this |
|
777 |
# changes, either this test must be skipped or the script must be updated. |
|
778 |
assert len(inodes) == 2 |
|
779 |
snode = inodes[1] |
|
780 |
else: |
|
776 | 781 |
# instance is not redundant, but we still need to pass a node |
777 | 782 |
# (which will be ignored) |
778 |
fsec = tnode |
|
779 |
else: |
|
780 |
fsec = snode |
|
783 |
snode = tnode |
|
784 |
pnode = inodes[0] |
|
781 | 785 |
# note: pnode:snode are the *current* nodes, so we move it first to |
782 | 786 |
# tnode:pnode, then back to pnode:snode |
783 | 787 |
for si, di, pn, sn in [(src_instance["name"], dest_instance["name"], |
784 | 788 |
tnode["primary"], pnode["primary"]), |
785 | 789 |
(dest_instance["name"], src_instance["name"], |
786 |
pnode["primary"], fsec["primary"])]:
|
|
790 |
pnode["primary"], snode["primary"])]:
|
|
787 | 791 |
cmd = [ |
788 | 792 |
"../tools/move-instance", |
789 | 793 |
"--verbose", |
Also available in: Unified diff