Revision 4b62db14

b/qa/ganeti-qa.py
211 211
        if qa_config.TestEnabled('instance-failover'):
212 212
          RunTest(qa_instance.TestInstanceFailover, instance)
213 213

  
214
        if qa_config.TestEnabled('node-evacuate'):
215
          RunTest(qa_node.TestNodeEvacuate, node, node2)
216

  
217
        if qa_config.TestEnabled('node-failover'):
218
          RunTest(qa_node.TestNodeFailover, node, node2)
219

  
214 220
        if qa_config.TestEnabled('node-volumes'):
215 221
          RunTest(qa_node.TestNodeVolumes)
216 222

  
b/qa/qa-sample.yaml
38 38
  node-info: True
39 39
  node-volumes: True
40 40

  
41
  # These tests need at least three nodes
42
  node-evacuate: False
43
  node-failover: False
44

  
41 45
  instance-add-plain-disk: True
42 46
  instance-add-local-mirror-disk: True
43 47
  instance-add-remote-raid-disk: True
b/qa/qa_config.py
96 96
  # TODO: Maybe combine filters
97 97
  if exclude is None:
98 98
    nodes = cfg['nodes'][:]
99
  elif isinstance(exclude, (list, tuple)):
100
    nodes = filter(lambda node: node not in exclude, cfg['nodes'])
99 101
  else:
100 102
    nodes = filter(lambda node: node != exclude, cfg['nodes'])
101 103

  
b/qa/qa_error.py
35 35

  
36 36
  """
37 37
  pass
38

  
39

  
40
class UnusableNodeError(Error):
41
  """Unusable node.
42

  
43
  """
44
  pass
b/qa/qa_node.py
20 20

  
21 21
import qa_config
22 22
import qa_error
23
import qa_utils
23 24

  
24 25
from qa_utils import AssertEqual, StartSSH
25 26

  
......
81 82
  cmd = ['gnt-node', 'volumes']
82 83
  AssertEqual(StartSSH(master['primary'],
83 84
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
85

  
86

  
87
def TestNodeFailover(node, node2):
88
  """gnt-node failover"""
89
  master = qa_config.GetMasterNode()
90

  
91
  if qa_utils.GetNodeInstances(node2):
92
    raise qa_errors.UnusableNodeError("Secondary node has at least one "
93
                                      "primary instance. This test requires "
94
                                      "it to have no primary instances.")
95

  
96
  # Fail over to secondary node
97
  cmd = ['gnt-node', 'failover', '-f', node['primary']]
98
  AssertEqual(StartSSH(master['primary'],
99
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
100

  
101
  # ... and back again.
102
  cmd = ['gnt-node', 'failover', '-f', node2['primary']]
103
  AssertEqual(StartSSH(master['primary'],
104
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
105

  
106

  
107
def TestNodeEvacuate(node, node2):
108
  """gnt-node evacuate"""
109
  master = qa_config.GetMasterNode()
110

  
111
  node3 = qa_config.AcquireNode(exclude=[node, node2])
112
  try:
113
    if qa_utils.GetNodeInstances(node3):
114
      raise qa_errors.UnusableNodeError("Evacuation node has at least one "
115
                                        "secondary instance. This test requires "
116
                                        "it to have no secondary instances.")
117

  
118
    # Evacuate all secondary instances
119
    cmd = ['gnt-node', 'evacuate', '-f', node2['primary'], node3['primary']]
120
    AssertEqual(StartSSH(master['primary'],
121
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
122

  
123
    # ... and back again.
124
    cmd = ['gnt-node', 'evacuate', '-f', node3['primary'], node2['primary']]
125
    AssertEqual(StartSSH(master['primary'],
126
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
127
  finally:
128
    qa_config.ReleaseNode(node3)
b/qa/qa_utils.py
100 100
  """Starts SSH.
101 101

  
102 102
  """
103
  args = GetSSHCommand(node, cmd, strict=strict)
104
  return subprocess.Popen(args, shell=False)
103
  return subprocess.Popen(GetSSHCommand(node, cmd, strict=strict),
104
                          shell=False)
105

  
106

  
107
def GetCommandOutput(node, cmd):
108
  """Returns the output of a command executed on the given node.
109

  
110
  """
111
  p = subprocess.Popen(GetSSHCommand(node, cmd),
112
                       shell=False, stdout=subprocess.PIPE)
113
  AssertEqual(p.wait(), 0)
114
  return p.stdout.read()
105 115

  
106 116

  
107 117
def UploadFile(node, src):
......
130 140
    f.close()
131 141

  
132 142

  
143
def _ResolveName(cmd, key):
144
  """Helper function.
145

  
146
  """
147
  master = qa_config.GetMasterNode()
148

  
149
  output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
150
  for line in output.splitlines():
151
    (lkey, lvalue) = line.split(':', 1)
152
    if lkey == key:
153
      return lvalue.lstrip()
154
  raise KeyError("Key not found")
155

  
156

  
133 157
def ResolveInstanceName(instance):
134 158
  """Gets the full name of an instance.
135 159

  
136 160
  """
161
  return _ResolveName(['gnt-instance', 'info', instance['info']],
162
                      'Instance name')
163

  
164

  
165
def ResolveNodeName(node):
166
  """Gets the full name of a node.
167

  
168
  """
169
  return _ResolveName(['gnt-node', 'info', node['primary']],
170
                      'Node name')
171

  
172

  
173
def GetNodeInstances(node, secondaries=False):
174
  """Gets a list of instances on a node.
175

  
176
  """
137 177
  master = qa_config.GetMasterNode()
138 178

  
139
  info_cmd = utils.ShellQuoteArgs(['gnt-instance', 'info', instance['name']])
140
  sed_cmd = utils.ShellQuoteArgs(['sed', '-n', '-e', 's/^Instance name: *//p'])
179
  node_name = ResolveNodeName(node)
141 180

  
142
  cmd = '%s | %s' % (info_cmd, sed_cmd)
143
  ssh_cmd = GetSSHCommand(master['primary'], cmd)
144
  p = subprocess.Popen(ssh_cmd, shell=False, stdout=subprocess.PIPE)
145
  AssertEqual(p.wait(), 0)
181
  # Get list of all instances
182
  cmd = ['gnt-instance', 'list', '--separator=:', '--no-headers',
183
         '--output=name,pnode,snodes']
184
  output = GetCommandOutput(master['primary'], utils.ShellQuoteArgs(cmd))
185

  
186
  instances = []
187
  for line in output.splitlines():
188
    (name, pnode, snodes) = line.split(':', 2)
189
    if ((not secondaries and pnode == node_name) or
190
        (secondaries and node_name in snodes.split(','))):
191
      instances.append(name)
146 192

  
147
  return p.stdout.read().strip()
193
  return instances
148 194

  
149 195

  
150 196
def _PrintWithColor(text, seq):

Also available in: Unified diff