Revision f006f110

b/qa/ganeti-qa.py
619 619
      pnode = qa_config.AcquireNode(exclude=snode)
620 620
      try:
621 621
        instance = qa_instance.TestInstanceAddWithDrbdDisk([pnode, snode])
622
        qa_node.MakeNodeOffline(snode, "yes")
623
        try:
624
          RunTest(qa_instance.TestInstanceRemove, instance)
625
        finally:
626
          qa_node.MakeNodeOffline(snode, "no")
622
        set_offline = lambda node: qa_node.MakeNodeOffline(node, "yes")
623
        set_online = lambda node: qa_node.MakeNodeOffline(node, "no")
624
        RunTest(qa_instance.TestRemoveInstanceOfflineNode, instance, snode,
625
                set_offline, set_online)
627 626
      finally:
628 627
        qa_config.ReleaseNode(pnode)
629 628
    finally:
630 629
      qa_config.ReleaseNode(snode)
631
    # FIXME: This test leaves a DRBD device and two LVs behind
632
    # Cluster-verify would fail
630
    qa_cluster.AssertClusterVerify()
633 631

  
634 632
  RunTestIf("create-cluster", qa_node.TestNodeRemoveAll)
635 633

  
b/qa/qa_instance.py
89 89

  
90 90
  @type instance: string
91 91
  @param instance: the instance name
92
  @return: a dictionary with two keys:
92
  @return: a dictionary with the following keys:
93 93
      - "nodes": instance nodes, a list of strings
94 94
      - "volumes": instance volume IDs, a list of strings
95
      - "drbd-minors": DRBD minors used by the instance, a dictionary where
96
        keys are nodes, and values are lists of integers (or an empty
97
        dictionary for non-DRBD instances)
95 98

  
96 99
  """
97 100
  master = qa_config.GetMasterNode()
......
106 109
  # FIXME This works with no more than 2 secondaries
107 110
  re_nodelist = re.compile(node_elem + "(?:," + node_elem + ")?$")
108 111
  re_vol = re.compile(r"^\s+logical_id:\s+(\S+)$")
112
  re_drbdnode = re.compile(r"^\s+node[AB]:\s+([^\s,]+),\s+minor=([0-9]+)$")
109 113
  nodes = []
110 114
  vols = []
115
  drbd_min = {}
111 116
  for line in info_out.splitlines():
112 117
    m = re_node.match(line)
113 118
    if m:
......
120 125
    m = re_vol.match(line)
121 126
    if m:
122 127
      vols.append(m.group(1))
128
    m = re_drbdnode.match(line)
129
    if m:
130
      node = m.group(1)
131
      minor = int(m.group(2))
132
      if drbd_min.get(node) is not None:
133
        drbd_min[node].append(minor)
134
      else:
135
        drbd_min[node] = [minor]
123 136
  assert vols
124 137
  assert nodes
125
  return {"nodes": nodes, "volumes": vols}
138
  return {"nodes": nodes, "volumes": vols, "drbd-minors": drbd_min}
126 139

  
127 140

  
128 141
def _DestroyInstanceVolumes(instance):
......
698 711
def TestBackupListFields():
699 712
  """gnt-backup list-fields"""
700 713
  qa_utils.GenericQueryFieldsTest("gnt-backup", query.EXPORT_FIELDS.keys())
714

  
715

  
716
def TestRemoveInstanceOfflineNode(instance, snode, set_offline, set_online):
717
  """gtn-instance remove with an off-line node
718

  
719
  @param instance: instance
720
  @param snode: secondary node, to be set offline
721
  @param set_offline: function to call to set the node off-line
722
  @param set_online: function to call to set the node on-line
723

  
724
  """
725
  info = _GetInstanceInfo(instance["name"])
726
  set_offline(snode)
727
  try:
728
    TestInstanceRemove(instance)
729
  finally:
730
    set_online(snode)
731
  # Clean up the disks on the offline node
732
  for minor in info["drbd-minors"][snode["primary"]]:
733
    AssertCommand(["drbdsetup", str(minor), "down"], node=snode)
734
  AssertCommand(["lvremove", "-f"] + info["volumes"], node=snode)

Also available in: Unified diff