Statistics
| Branch: | Tag: | Revision:

root / testing / ganeti.qa.py @ 2a710df1

History | View | Annotate | Download (19.6 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 94508060 Michael Hanselmann
"""Script for doing Q&A on Ganeti
23 94508060 Michael Hanselmann

24 94508060 Michael Hanselmann
You can create the required known_hosts file using ssh-keyscan. It's mandatory
25 94508060 Michael Hanselmann
to use the full name of a node (FQDN). For security reasons, verify the keys
26 94508060 Michael Hanselmann
before using them.
27 94508060 Michael Hanselmann
Example: ssh-keyscan -t rsa node{1,2,3,4}.example.com > known_hosts
28 94508060 Michael Hanselmann
"""
29 a8083063 Iustin Pop
30 a8083063 Iustin Pop
import os
31 a8083063 Iustin Pop
import re
32 a8083063 Iustin Pop
import sys
33 a8083063 Iustin Pop
import yaml
34 a8083063 Iustin Pop
import time
35 180bdd1f Michael Hanselmann
import tempfile
36 a8083063 Iustin Pop
from datetime import datetime
37 a8083063 Iustin Pop
from optparse import OptionParser
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
# I want more flexibility for testing over SSH, therefore I'm not using
40 a8083063 Iustin Pop
# Ganeti's ssh module.
41 a8083063 Iustin Pop
import subprocess
42 a8083063 Iustin Pop
43 a8083063 Iustin Pop
from ganeti import utils
44 a8083063 Iustin Pop
from ganeti import constants
45 a8083063 Iustin Pop
46 a8083063 Iustin Pop
# {{{ Global variables
47 a8083063 Iustin Pop
cfg = None
48 a8083063 Iustin Pop
options = None
49 a8083063 Iustin Pop
# }}}
50 a8083063 Iustin Pop
51 a8083063 Iustin Pop
# {{{ Errors
52 a8083063 Iustin Pop
class Error(Exception):
53 a8083063 Iustin Pop
  """An error occurred during Q&A testing.
54 a8083063 Iustin Pop

55 a8083063 Iustin Pop
  """
56 a8083063 Iustin Pop
  pass
57 a8083063 Iustin Pop
58 a8083063 Iustin Pop
59 a8083063 Iustin Pop
class OutOfNodesError(Error):
60 a8083063 Iustin Pop
  """Out of nodes.
61 a8083063 Iustin Pop

62 a8083063 Iustin Pop
  """
63 a8083063 Iustin Pop
  pass
64 a8083063 Iustin Pop
65 a8083063 Iustin Pop
66 a8083063 Iustin Pop
class OutOfInstancesError(Error):
67 a8083063 Iustin Pop
  """Out of instances.
68 a8083063 Iustin Pop

69 a8083063 Iustin Pop
  """
70 a8083063 Iustin Pop
  pass
71 a8083063 Iustin Pop
# }}}
72 a8083063 Iustin Pop
73 a8083063 Iustin Pop
# {{{ Utilities
74 a8083063 Iustin Pop
def TestEnabled(test):
75 a8083063 Iustin Pop
  """Returns True if the given test is enabled."""
76 a8083063 Iustin Pop
  return cfg.get('tests', {}).get(test, False)
77 a8083063 Iustin Pop
78 a8083063 Iustin Pop
79 a8083063 Iustin Pop
def RunTest(callable, *args):
80 a8083063 Iustin Pop
  """Runs a test after printing a header.
81 a8083063 Iustin Pop

82 a8083063 Iustin Pop
  """
83 a8083063 Iustin Pop
  if callable.__doc__:
84 a8083063 Iustin Pop
    desc = callable.__doc__.splitlines()[0].strip()
85 a8083063 Iustin Pop
  else:
86 a8083063 Iustin Pop
    desc = '%r' % callable
87 a8083063 Iustin Pop
88 a8083063 Iustin Pop
  now = str(datetime.now())
89 a8083063 Iustin Pop
90 a8083063 Iustin Pop
  print
91 a8083063 Iustin Pop
  print '---', now, ('-' * (55 - len(now)))
92 a8083063 Iustin Pop
  print desc
93 a8083063 Iustin Pop
  print '-' * 60
94 a8083063 Iustin Pop
95 a8083063 Iustin Pop
  return callable(*args)
96 a8083063 Iustin Pop
97 a8083063 Iustin Pop
98 a8083063 Iustin Pop
def AssertEqual(first, second, msg=None):
99 a8083063 Iustin Pop
  """Raises an error when values aren't equal.
100 a8083063 Iustin Pop

101 a8083063 Iustin Pop
  """
102 a8083063 Iustin Pop
  if not first == second:
103 3ecf6786 Iustin Pop
    raise Error(msg or '%r == %r' % (first, second))
104 a8083063 Iustin Pop
105 a8083063 Iustin Pop
106 a8083063 Iustin Pop
def GetSSHCommand(node, cmd, strict=True):
107 a8083063 Iustin Pop
  """Builds SSH command to be executed.
108 a8083063 Iustin Pop

109 a8083063 Iustin Pop
  """
110 a8083063 Iustin Pop
  args = [ 'ssh', '-oEscapeChar=none', '-oBatchMode=yes', '-l', 'root' ]
111 a8083063 Iustin Pop
112 a8083063 Iustin Pop
  if strict:
113 a8083063 Iustin Pop
    tmp = 'yes'
114 a8083063 Iustin Pop
  else:
115 a8083063 Iustin Pop
    tmp = 'no'
116 a8083063 Iustin Pop
  args.append('-oStrictHostKeyChecking=%s' % tmp)
117 807d926c Michael Hanselmann
  args.append('-oClearAllForwardings=yes')
118 807d926c Michael Hanselmann
  args.append('-oForwardAgent=yes')
119 a8083063 Iustin Pop
  args.append(node)
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  if options.dry_run:
122 a8083063 Iustin Pop
    prefix = 'exit 0; '
123 a8083063 Iustin Pop
  else:
124 a8083063 Iustin Pop
    prefix = ''
125 a8083063 Iustin Pop
126 a8083063 Iustin Pop
  args.append(prefix + cmd)
127 a8083063 Iustin Pop
128 180bdd1f Michael Hanselmann
  print 'SSH:', utils.ShellQuoteArgs(args)
129 a8083063 Iustin Pop
130 a8083063 Iustin Pop
  return args
131 a8083063 Iustin Pop
132 a8083063 Iustin Pop
133 a8083063 Iustin Pop
def StartSSH(node, cmd, strict=True):
134 a8083063 Iustin Pop
  """Starts SSH.
135 a8083063 Iustin Pop

136 a8083063 Iustin Pop
  """
137 a8083063 Iustin Pop
  args = GetSSHCommand(node, cmd, strict=strict)
138 a8083063 Iustin Pop
  return subprocess.Popen(args, shell=False)
139 a8083063 Iustin Pop
140 a8083063 Iustin Pop
141 a8083063 Iustin Pop
def UploadFile(node, file):
142 a8083063 Iustin Pop
  """Uploads a file to a node and returns the filename.
143 a8083063 Iustin Pop

144 180bdd1f Michael Hanselmann
  Caller needs to remove the returned file on the node when it's not needed
145 180bdd1f Michael Hanselmann
  anymore.
146 a8083063 Iustin Pop
  """
147 180bdd1f Michael Hanselmann
  # Make sure nobody else has access to it while preserving local permissions
148 180bdd1f Michael Hanselmann
  mode = os.stat(file).st_mode & 0700
149 a8083063 Iustin Pop
150 180bdd1f Michael Hanselmann
  cmd = ('tmp=$(tempfile --mode %o --prefix gnt) && '
151 a8083063 Iustin Pop
         '[[ -f "${tmp}" ]] && '
152 a8083063 Iustin Pop
         'cat > "${tmp}" && '
153 a8083063 Iustin Pop
         'echo "${tmp}"') % mode
154 a8083063 Iustin Pop
155 a8083063 Iustin Pop
  f = open(file, 'r')
156 a8083063 Iustin Pop
  try:
157 a8083063 Iustin Pop
    p = subprocess.Popen(GetSSHCommand(node, cmd), shell=False, stdin=f,
158 a8083063 Iustin Pop
                         stdout=subprocess.PIPE)
159 a8083063 Iustin Pop
    AssertEqual(p.wait(), 0)
160 a8083063 Iustin Pop
161 180bdd1f Michael Hanselmann
    # Return temporary filename
162 180bdd1f Michael Hanselmann
    return p.stdout.read().strip()
163 a8083063 Iustin Pop
  finally:
164 a8083063 Iustin Pop
    f.close()
165 a8083063 Iustin Pop
# }}}
166 a8083063 Iustin Pop
167 a8083063 Iustin Pop
# {{{ Config helpers
168 a8083063 Iustin Pop
def GetMasterNode():
169 a8083063 Iustin Pop
  return cfg['nodes'][0]
170 a8083063 Iustin Pop
171 a8083063 Iustin Pop
172 a8083063 Iustin Pop
def AcquireInstance():
173 a8083063 Iustin Pop
  """Returns an instance which isn't in use.
174 a8083063 Iustin Pop

175 a8083063 Iustin Pop
  """
176 a8083063 Iustin Pop
  # Filter out unwanted instances
177 a8083063 Iustin Pop
  tmp_flt = lambda inst: not inst.get('_used', False)
178 a8083063 Iustin Pop
  instances = filter(tmp_flt, cfg['instances'])
179 a8083063 Iustin Pop
  del tmp_flt
180 a8083063 Iustin Pop
181 a8083063 Iustin Pop
  if len(instances) == 0:
182 3ecf6786 Iustin Pop
    raise OutOfInstancesError("No instances left")
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
  inst = instances[0]
185 a8083063 Iustin Pop
  inst['_used'] = True
186 a8083063 Iustin Pop
  return inst
187 a8083063 Iustin Pop
188 a8083063 Iustin Pop
189 a8083063 Iustin Pop
def ReleaseInstance(inst):
190 a8083063 Iustin Pop
  inst['_used'] = False
191 a8083063 Iustin Pop
192 a8083063 Iustin Pop
193 a8083063 Iustin Pop
def AcquireNode(exclude=None):
194 a8083063 Iustin Pop
  """Returns the least used node.
195 a8083063 Iustin Pop

196 a8083063 Iustin Pop
  """
197 a8083063 Iustin Pop
  master = GetMasterNode()
198 a8083063 Iustin Pop
199 a8083063 Iustin Pop
  # Filter out unwanted nodes
200 a8083063 Iustin Pop
  # TODO: Maybe combine filters
201 a8083063 Iustin Pop
  if exclude is None:
202 a8083063 Iustin Pop
    nodes = cfg['nodes'][:]
203 a8083063 Iustin Pop
  else:
204 a8083063 Iustin Pop
    nodes = filter(lambda node: node != exclude, cfg['nodes'])
205 a8083063 Iustin Pop
206 a8083063 Iustin Pop
  tmp_flt = lambda node: node.get('_added', False) or node == master
207 a8083063 Iustin Pop
  nodes = filter(tmp_flt, nodes)
208 a8083063 Iustin Pop
  del tmp_flt
209 a8083063 Iustin Pop
210 a8083063 Iustin Pop
  if len(nodes) == 0:
211 3ecf6786 Iustin Pop
    raise OutOfNodesError("No nodes left")
212 a8083063 Iustin Pop
213 a8083063 Iustin Pop
  # Get node with least number of uses
214 a8083063 Iustin Pop
  def compare(a, b):
215 a8083063 Iustin Pop
    result = cmp(a.get('_count', 0), b.get('_count', 0))
216 a8083063 Iustin Pop
    if result == 0:
217 a8083063 Iustin Pop
      result = cmp(a['primary'], b['primary'])
218 a8083063 Iustin Pop
    return result
219 a8083063 Iustin Pop
220 a8083063 Iustin Pop
  nodes.sort(cmp=compare)
221 a8083063 Iustin Pop
222 a8083063 Iustin Pop
  node = nodes[0]
223 a8083063 Iustin Pop
  node['_count'] = node.get('_count', 0) + 1
224 a8083063 Iustin Pop
  return node
225 a8083063 Iustin Pop
226 a8083063 Iustin Pop
227 a8083063 Iustin Pop
def ReleaseNode(node):
228 a8083063 Iustin Pop
  node['_count'] = node.get('_count', 0) - 1
229 a8083063 Iustin Pop
# }}}
230 a8083063 Iustin Pop
231 a8083063 Iustin Pop
# {{{ Environment tests
232 a8083063 Iustin Pop
def TestConfig():
233 a8083063 Iustin Pop
  """Test configuration for sanity.
234 a8083063 Iustin Pop

235 a8083063 Iustin Pop
  """
236 a8083063 Iustin Pop
  if len(cfg['nodes']) < 1:
237 3ecf6786 Iustin Pop
    raise Error("Need at least one node")
238 a8083063 Iustin Pop
  if len(cfg['instances']) < 1:
239 3ecf6786 Iustin Pop
    raise Error("Need at least one instance")
240 a8083063 Iustin Pop
  # TODO: Add more checks
241 a8083063 Iustin Pop
242 a8083063 Iustin Pop
243 a8083063 Iustin Pop
def TestSshConnection():
244 a8083063 Iustin Pop
  """Test SSH connection.
245 a8083063 Iustin Pop

246 a8083063 Iustin Pop
  """
247 a8083063 Iustin Pop
  for node in cfg['nodes']:
248 a8083063 Iustin Pop
    AssertEqual(StartSSH(node['primary'], 'exit').wait(), 0)
249 a8083063 Iustin Pop
250 a8083063 Iustin Pop
251 a8083063 Iustin Pop
def TestGanetiCommands():
252 a8083063 Iustin Pop
  """Test availibility of Ganeti commands.
253 a8083063 Iustin Pop

254 a8083063 Iustin Pop
  """
255 a8083063 Iustin Pop
  cmds = ( ['gnt-cluster', '--version'],
256 a8083063 Iustin Pop
           ['gnt-os', '--version'],
257 a8083063 Iustin Pop
           ['gnt-node', '--version'],
258 a8083063 Iustin Pop
           ['gnt-instance', '--version'],
259 a8083063 Iustin Pop
           ['gnt-backup', '--version'],
260 a8083063 Iustin Pop
           ['ganeti-noded', '--version'],
261 a8083063 Iustin Pop
           ['ganeti-watcher', '--version'] )
262 a8083063 Iustin Pop
263 e9e35aaa Michael Hanselmann
  cmd = ' && '.join([utils.ShellQuoteArgs(i) for i in cmds])
264 a8083063 Iustin Pop
265 a8083063 Iustin Pop
  for node in cfg['nodes']:
266 a8083063 Iustin Pop
    AssertEqual(StartSSH(node['primary'], cmd).wait(), 0)
267 a8083063 Iustin Pop
268 a8083063 Iustin Pop
269 a8083063 Iustin Pop
def TestIcmpPing():
270 a8083063 Iustin Pop
  """ICMP ping each node.
271 a8083063 Iustin Pop

272 a8083063 Iustin Pop
  """
273 a8083063 Iustin Pop
  for node in cfg['nodes']:
274 a8083063 Iustin Pop
    check = []
275 a8083063 Iustin Pop
    for i in cfg['nodes']:
276 a8083063 Iustin Pop
      check.append(i['primary'])
277 a8083063 Iustin Pop
      if i.has_key('secondary'):
278 a8083063 Iustin Pop
        check.append(i['secondary'])
279 a8083063 Iustin Pop
280 a8083063 Iustin Pop
    ping = lambda ip: utils.ShellQuoteArgs(['ping', '-w', '3', '-c', '1', ip])
281 e9e35aaa Michael Hanselmann
    cmd = ' && '.join([ping(i) for i in check])
282 a8083063 Iustin Pop
283 a8083063 Iustin Pop
    AssertEqual(StartSSH(node['primary'], cmd).wait(), 0)
284 a8083063 Iustin Pop
# }}}
285 a8083063 Iustin Pop
286 a8083063 Iustin Pop
# {{{ Cluster tests
287 a8083063 Iustin Pop
def TestClusterInit():
288 a8083063 Iustin Pop
  """gnt-cluster init"""
289 a8083063 Iustin Pop
  master = GetMasterNode()
290 a8083063 Iustin Pop
291 a8083063 Iustin Pop
  cmd = ['gnt-cluster', 'init']
292 a8083063 Iustin Pop
  if master.get('secondary', None):
293 a8083063 Iustin Pop
    cmd.append('--secondary-ip=%s' % master['secondary'])
294 6f11f250 Michael Hanselmann
  if cfg.get('bridge', None):
295 6f11f250 Michael Hanselmann
    cmd.append('--bridge=%s' % cfg['bridge'])
296 e9e35aaa Michael Hanselmann
    cmd.append('--master-netdev=%s' % cfg['bridge'])
297 a8083063 Iustin Pop
  cmd.append(cfg['name'])
298 a8083063 Iustin Pop
299 a8083063 Iustin Pop
  AssertEqual(StartSSH(master['primary'],
300 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
303 a8083063 Iustin Pop
def TestClusterVerify():
304 a8083063 Iustin Pop
  """gnt-cluster verify"""
305 a8083063 Iustin Pop
  cmd = ['gnt-cluster', 'verify']
306 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
307 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
308 a8083063 Iustin Pop
309 a8083063 Iustin Pop
310 a8083063 Iustin Pop
def TestClusterInfo():
311 a8083063 Iustin Pop
  """gnt-cluster info"""
312 a8083063 Iustin Pop
  cmd = ['gnt-cluster', 'info']
313 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
314 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
315 a8083063 Iustin Pop
316 a8083063 Iustin Pop
317 a8083063 Iustin Pop
def TestClusterBurnin():
318 a8083063 Iustin Pop
  """Burnin"""
319 a8083063 Iustin Pop
  master = GetMasterNode()
320 a8083063 Iustin Pop
321 a8083063 Iustin Pop
  # Get as many instances as we need
322 a8083063 Iustin Pop
  instances = []
323 a8083063 Iustin Pop
  try:
324 a8083063 Iustin Pop
    for _ in xrange(0, cfg.get('options', {}).get('burnin-instances', 1)):
325 a8083063 Iustin Pop
      instances.append(AcquireInstance())
326 a8083063 Iustin Pop
  except OutOfInstancesError:
327 a8083063 Iustin Pop
    print "Not enough instances, continuing anyway."
328 a8083063 Iustin Pop
329 a8083063 Iustin Pop
  if len(instances) < 1:
330 3ecf6786 Iustin Pop
    raise Error("Burnin needs at least one instance")
331 a8083063 Iustin Pop
332 a8083063 Iustin Pop
  # Run burnin
333 a8083063 Iustin Pop
  try:
334 a8083063 Iustin Pop
    script = UploadFile(master['primary'], '../tools/burnin')
335 a8083063 Iustin Pop
    try:
336 a8083063 Iustin Pop
      cmd = [script, '--os=%s' % cfg['os']]
337 e9e35aaa Michael Hanselmann
      cmd += [inst['name'] for inst in instances]
338 a8083063 Iustin Pop
      AssertEqual(StartSSH(master['primary'],
339 a8083063 Iustin Pop
                           utils.ShellQuoteArgs(cmd)).wait(), 0)
340 a8083063 Iustin Pop
    finally:
341 a8083063 Iustin Pop
      cmd = ['rm', '-f', script]
342 a8083063 Iustin Pop
      AssertEqual(StartSSH(master['primary'],
343 a8083063 Iustin Pop
                           utils.ShellQuoteArgs(cmd)).wait(), 0)
344 a8083063 Iustin Pop
  finally:
345 a8083063 Iustin Pop
    for inst in instances:
346 a8083063 Iustin Pop
      ReleaseInstance(inst)
347 a8083063 Iustin Pop
348 a8083063 Iustin Pop
349 a8083063 Iustin Pop
def TestClusterMasterFailover():
350 a8083063 Iustin Pop
  """gnt-cluster masterfailover"""
351 a8083063 Iustin Pop
  master = GetMasterNode()
352 a8083063 Iustin Pop
353 a8083063 Iustin Pop
  failovermaster = AcquireNode(exclude=master)
354 a8083063 Iustin Pop
  try:
355 a8083063 Iustin Pop
    cmd = ['gnt-cluster', 'masterfailover']
356 a8083063 Iustin Pop
    AssertEqual(StartSSH(failovermaster['primary'],
357 a8083063 Iustin Pop
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
358 a8083063 Iustin Pop
359 a8083063 Iustin Pop
    cmd = ['gnt-cluster', 'masterfailover']
360 a8083063 Iustin Pop
    AssertEqual(StartSSH(master['primary'],
361 a8083063 Iustin Pop
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
362 a8083063 Iustin Pop
  finally:
363 a8083063 Iustin Pop
    ReleaseNode(failovermaster)
364 a8083063 Iustin Pop
365 a8083063 Iustin Pop
366 180bdd1f Michael Hanselmann
def TestClusterCopyfile():
367 180bdd1f Michael Hanselmann
  """gnt-cluster copyfile"""
368 180bdd1f Michael Hanselmann
  master = GetMasterNode()
369 180bdd1f Michael Hanselmann
370 180bdd1f Michael Hanselmann
  # Create temporary file
371 180bdd1f Michael Hanselmann
  f = tempfile.NamedTemporaryFile()
372 180bdd1f Michael Hanselmann
  f.write("I'm a testfile.\n")
373 180bdd1f Michael Hanselmann
  f.flush()
374 180bdd1f Michael Hanselmann
  f.seek(0)
375 180bdd1f Michael Hanselmann
376 180bdd1f Michael Hanselmann
  # Upload file to master node
377 180bdd1f Michael Hanselmann
  testname = UploadFile(master['primary'], f.name)
378 180bdd1f Michael Hanselmann
  try:
379 180bdd1f Michael Hanselmann
    # Copy file to all nodes
380 180bdd1f Michael Hanselmann
    cmd = ['gnt-cluster', 'copyfile', testname]
381 180bdd1f Michael Hanselmann
    AssertEqual(StartSSH(master['primary'],
382 180bdd1f Michael Hanselmann
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
383 180bdd1f Michael Hanselmann
  finally:
384 180bdd1f Michael Hanselmann
    # Remove file from all nodes
385 180bdd1f Michael Hanselmann
    for node in cfg['nodes']:
386 180bdd1f Michael Hanselmann
      cmd = ['rm', '-f', testname]
387 180bdd1f Michael Hanselmann
      AssertEqual(StartSSH(node['primary'],
388 180bdd1f Michael Hanselmann
                           utils.ShellQuoteArgs(cmd)).wait(), 0)
389 180bdd1f Michael Hanselmann
390 180bdd1f Michael Hanselmann
391 a8083063 Iustin Pop
def TestClusterDestroy():
392 a8083063 Iustin Pop
  """gnt-cluster destroy"""
393 a8083063 Iustin Pop
  cmd = ['gnt-cluster', 'destroy', '--yes-do-it']
394 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
395 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
396 a8083063 Iustin Pop
# }}}
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
# {{{ Node tests
399 a8083063 Iustin Pop
def _NodeAdd(node):
400 a8083063 Iustin Pop
  if node.get('_added', False):
401 3ecf6786 Iustin Pop
    raise Error("Node %s already in cluster" % node['primary'])
402 a8083063 Iustin Pop
403 a8083063 Iustin Pop
  cmd = ['gnt-node', 'add']
404 a8083063 Iustin Pop
  if node.get('secondary', None):
405 a8083063 Iustin Pop
    cmd.append('--secondary-ip=%s' % node['secondary'])
406 a8083063 Iustin Pop
  cmd.append(node['primary'])
407 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
408 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
409 a8083063 Iustin Pop
410 a8083063 Iustin Pop
  node['_added'] = True
411 a8083063 Iustin Pop
412 a8083063 Iustin Pop
413 a8083063 Iustin Pop
def TestNodeAddAll():
414 a8083063 Iustin Pop
  """Adding all nodes to cluster."""
415 a8083063 Iustin Pop
  master = GetMasterNode()
416 a8083063 Iustin Pop
  for node in cfg['nodes']:
417 a8083063 Iustin Pop
    if node != master:
418 a8083063 Iustin Pop
      _NodeAdd(node)
419 a8083063 Iustin Pop
420 a8083063 Iustin Pop
421 a8083063 Iustin Pop
def _NodeRemove(node):
422 a8083063 Iustin Pop
  cmd = ['gnt-node', 'remove', node['primary']]
423 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
424 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
425 a8083063 Iustin Pop
  node['_added'] = False
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
428 a8083063 Iustin Pop
def TestNodeRemoveAll():
429 a8083063 Iustin Pop
  """Removing all nodes from cluster."""
430 a8083063 Iustin Pop
  master = GetMasterNode()
431 a8083063 Iustin Pop
  for node in cfg['nodes']:
432 a8083063 Iustin Pop
    if node != master:
433 a8083063 Iustin Pop
      _NodeRemove(node)
434 e9e35aaa Michael Hanselmann
435 e9e35aaa Michael Hanselmann
436 e9e35aaa Michael Hanselmann
def TestNodeInfo():
437 e9e35aaa Michael Hanselmann
  """gnt-node info"""
438 e9e35aaa Michael Hanselmann
  cmd = ['gnt-node', 'info']
439 e9e35aaa Michael Hanselmann
  AssertEqual(StartSSH(GetMasterNode()['primary'],
440 e9e35aaa Michael Hanselmann
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
441 a8083063 Iustin Pop
# }}}
442 a8083063 Iustin Pop
443 a8083063 Iustin Pop
# {{{ Instance tests
444 a8083063 Iustin Pop
def _DiskTest(node, instance, args):
445 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'add',
446 a8083063 Iustin Pop
         '--os-type=%s' % cfg['os'],
447 a8083063 Iustin Pop
         '--os-size=%s' % cfg['os-size'],
448 a8083063 Iustin Pop
         '--swap-size=%s' % cfg['swap-size'],
449 a8083063 Iustin Pop
         '--memory=%s' % cfg['mem'],
450 a8083063 Iustin Pop
         '--node=%s' % node['primary']]
451 a8083063 Iustin Pop
  if args:
452 a8083063 Iustin Pop
    cmd += args
453 a8083063 Iustin Pop
  cmd.append(instance['name'])
454 a8083063 Iustin Pop
455 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
456 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
457 a8083063 Iustin Pop
  return instance
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
460 a8083063 Iustin Pop
def TestInstanceAddWithPlainDisk(node):
461 a8083063 Iustin Pop
  """gnt-instance add -t plain"""
462 a8083063 Iustin Pop
  return _DiskTest(node, AcquireInstance(), ['--disk-template=plain'])
463 a8083063 Iustin Pop
464 a8083063 Iustin Pop
465 a8083063 Iustin Pop
def TestInstanceAddWithLocalMirrorDisk(node):
466 a8083063 Iustin Pop
  """gnt-instance add -t local_raid1"""
467 a8083063 Iustin Pop
  return _DiskTest(node, AcquireInstance(), ['--disk-template=local_raid1'])
468 a8083063 Iustin Pop
469 a8083063 Iustin Pop
470 a8083063 Iustin Pop
def TestInstanceAddWithRemoteRaidDisk(node, node2):
471 a8083063 Iustin Pop
  """gnt-instance add -t remote_raid1"""
472 a8083063 Iustin Pop
  return _DiskTest(node, AcquireInstance(),
473 a8083063 Iustin Pop
                   ['--disk-template=remote_raid1',
474 a8083063 Iustin Pop
                    '--secondary-node=%s' % node2['primary']])
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
477 a8083063 Iustin Pop
def TestInstanceRemove(instance):
478 a8083063 Iustin Pop
  """gnt-instance remove"""
479 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'remove', '-f', instance['name']]
480 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
481 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
482 a8083063 Iustin Pop
483 a8083063 Iustin Pop
  ReleaseInstance(instance)
484 a8083063 Iustin Pop
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
def TestInstanceStartup(instance):
487 a8083063 Iustin Pop
  """gnt-instance startup"""
488 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'startup', instance['name']]
489 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
490 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
491 a8083063 Iustin Pop
492 a8083063 Iustin Pop
493 a8083063 Iustin Pop
def TestInstanceShutdown(instance):
494 a8083063 Iustin Pop
  """gnt-instance shutdown"""
495 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'shutdown', instance['name']]
496 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
497 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
500 a8083063 Iustin Pop
def TestInstanceFailover(instance):
501 a8083063 Iustin Pop
  """gnt-instance failover"""
502 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'failover', '--force', instance['name']]
503 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
504 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
505 e9e35aaa Michael Hanselmann
506 e9e35aaa Michael Hanselmann
507 e9e35aaa Michael Hanselmann
def TestInstanceInfo(instance):
508 e9e35aaa Michael Hanselmann
  """gnt-instance info"""
509 e9e35aaa Michael Hanselmann
  cmd = ['gnt-instance', 'info', instance['name']]
510 e9e35aaa Michael Hanselmann
  AssertEqual(StartSSH(GetMasterNode()['primary'],
511 e9e35aaa Michael Hanselmann
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
512 a8083063 Iustin Pop
# }}}
513 a8083063 Iustin Pop
514 a8083063 Iustin Pop
# {{{ Daemon tests
515 a8083063 Iustin Pop
def _ResolveInstanceName(instance):
516 a8083063 Iustin Pop
  """Gets the full Xen name of an instance.
517 a8083063 Iustin Pop

518 a8083063 Iustin Pop
  """
519 a8083063 Iustin Pop
  master = GetMasterNode()
520 a8083063 Iustin Pop
521 a8083063 Iustin Pop
  info_cmd = utils.ShellQuoteArgs(['gnt-instance', 'info', instance['name']])
522 a8083063 Iustin Pop
  sed_cmd = utils.ShellQuoteArgs(['sed', '-n', '-e', 's/^Instance name: *//p'])
523 a8083063 Iustin Pop
524 a8083063 Iustin Pop
  cmd = '%s | %s' % (info_cmd, sed_cmd)
525 a8083063 Iustin Pop
  p = subprocess.Popen(GetSSHCommand(master['primary'], cmd), shell=False,
526 a8083063 Iustin Pop
                       stdout=subprocess.PIPE)
527 a8083063 Iustin Pop
  AssertEqual(p.wait(), 0)
528 a8083063 Iustin Pop
529 a8083063 Iustin Pop
  return p.stdout.read().strip()
530 a8083063 Iustin Pop
531 a8083063 Iustin Pop
532 a8083063 Iustin Pop
def _InstanceRunning(node, name):
533 a8083063 Iustin Pop
  """Checks whether an instance is running.
534 a8083063 Iustin Pop

535 a8083063 Iustin Pop
  Args:
536 a8083063 Iustin Pop
    node: Node the instance runs on
537 a8083063 Iustin Pop
    name: Full name of Xen instance
538 a8083063 Iustin Pop
  """
539 a8083063 Iustin Pop
  cmd = utils.ShellQuoteArgs(['xm', 'list', name]) + ' >/dev/null'
540 a8083063 Iustin Pop
  ret = StartSSH(node['primary'], cmd).wait()
541 a8083063 Iustin Pop
  return ret == 0
542 a8083063 Iustin Pop
543 a8083063 Iustin Pop
544 a8083063 Iustin Pop
def _XmShutdownInstance(node, name):
545 a8083063 Iustin Pop
  """Shuts down instance using "xm" and waits for completion.
546 a8083063 Iustin Pop

547 a8083063 Iustin Pop
  Args:
548 a8083063 Iustin Pop
    node: Node the instance runs on
549 a8083063 Iustin Pop
    name: Full name of Xen instance
550 a8083063 Iustin Pop
  """
551 a8083063 Iustin Pop
  cmd = ['xm', 'shutdown', name]
552 a8083063 Iustin Pop
  AssertEqual(StartSSH(GetMasterNode()['primary'],
553 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
554 a8083063 Iustin Pop
555 a8083063 Iustin Pop
  # Wait up to a minute
556 a8083063 Iustin Pop
  end = time.time() + 60
557 a8083063 Iustin Pop
  while time.time() <= end:
558 a8083063 Iustin Pop
    if not _InstanceRunning(node, name):
559 a8083063 Iustin Pop
      break
560 a8083063 Iustin Pop
    time.sleep(5)
561 a8083063 Iustin Pop
  else:
562 3ecf6786 Iustin Pop
    raise Error("xm shutdown failed")
563 a8083063 Iustin Pop
564 a8083063 Iustin Pop
565 a8083063 Iustin Pop
def _ResetWatcherDaemon(node):
566 a8083063 Iustin Pop
  """Removes the watcher daemon's state file.
567 a8083063 Iustin Pop

568 a8083063 Iustin Pop
  Args:
569 a8083063 Iustin Pop
    node: Node to be reset
570 a8083063 Iustin Pop
  """
571 a8083063 Iustin Pop
  cmd = ['rm', '-f', constants.WATCHER_STATEFILE]
572 a8083063 Iustin Pop
  AssertEqual(StartSSH(node['primary'],
573 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
574 a8083063 Iustin Pop
575 a8083063 Iustin Pop
576 a8083063 Iustin Pop
def TestInstanceAutomaticRestart(node, instance):
577 a8083063 Iustin Pop
  """Test automatic restart of instance by ganeti-watcher.
578 a8083063 Iustin Pop

579 a8083063 Iustin Pop
  Note: takes up to 6 minutes to complete.
580 a8083063 Iustin Pop
  """
581 a8083063 Iustin Pop
  master = GetMasterNode()
582 a8083063 Iustin Pop
  inst_name = _ResolveInstanceName(instance)
583 a8083063 Iustin Pop
584 a8083063 Iustin Pop
  _ResetWatcherDaemon(node)
585 a8083063 Iustin Pop
  _XmShutdownInstance(node, inst_name)
586 a8083063 Iustin Pop
587 a8083063 Iustin Pop
  # Give it a bit more than five minutes to start again
588 a8083063 Iustin Pop
  restart_at = time.time() + 330
589 a8083063 Iustin Pop
590 a8083063 Iustin Pop
  # Wait until it's running again
591 a8083063 Iustin Pop
  while time.time() <= restart_at:
592 a8083063 Iustin Pop
    if _InstanceRunning(node, inst_name):
593 a8083063 Iustin Pop
      break
594 a8083063 Iustin Pop
    time.sleep(15)
595 a8083063 Iustin Pop
  else:
596 3ecf6786 Iustin Pop
    raise Error("Daemon didn't restart instance in time")
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'info', inst_name]
599 a8083063 Iustin Pop
  AssertEqual(StartSSH(master['primary'],
600 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
601 a8083063 Iustin Pop
602 a8083063 Iustin Pop
603 a8083063 Iustin Pop
def TestInstanceConsecutiveFailures(node, instance):
604 a8083063 Iustin Pop
  """Test five consecutive instance failures.
605 a8083063 Iustin Pop

606 a8083063 Iustin Pop
  Note: takes at least 35 minutes to complete.
607 a8083063 Iustin Pop
  """
608 a8083063 Iustin Pop
  master = GetMasterNode()
609 a8083063 Iustin Pop
  inst_name = _ResolveInstanceName(instance)
610 a8083063 Iustin Pop
611 a8083063 Iustin Pop
  _ResetWatcherDaemon(node)
612 a8083063 Iustin Pop
  _XmShutdownInstance(node, inst_name)
613 a8083063 Iustin Pop
614 a8083063 Iustin Pop
  # Do shutdowns for 30 minutes
615 a8083063 Iustin Pop
  finished_at = time.time() + (35 * 60)
616 a8083063 Iustin Pop
617 a8083063 Iustin Pop
  while time.time() <= finished_at:
618 a8083063 Iustin Pop
    if _InstanceRunning(node, inst_name):
619 a8083063 Iustin Pop
      _XmShutdownInstance(node, inst_name)
620 a8083063 Iustin Pop
    time.sleep(30)
621 a8083063 Iustin Pop
622 a8083063 Iustin Pop
  # Check for some time whether the instance doesn't start again
623 a8083063 Iustin Pop
  check_until = time.time() + 330
624 a8083063 Iustin Pop
  while time.time() <= check_until:
625 a8083063 Iustin Pop
    if _InstanceRunning(node, inst_name):
626 3ecf6786 Iustin Pop
      raise Error("Instance started when it shouldn't")
627 a8083063 Iustin Pop
    time.sleep(30)
628 a8083063 Iustin Pop
629 a8083063 Iustin Pop
  cmd = ['gnt-instance', 'info', inst_name]
630 a8083063 Iustin Pop
  AssertEqual(StartSSH(master['primary'],
631 a8083063 Iustin Pop
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
632 a8083063 Iustin Pop
# }}}
633 a8083063 Iustin Pop
634 94508060 Michael Hanselmann
# {{{ Other tests
635 94508060 Michael Hanselmann
def TestUploadKnownHostsFile(localpath):
636 94508060 Michael Hanselmann
  """Uploading known_hosts file.
637 94508060 Michael Hanselmann

638 94508060 Michael Hanselmann
  """
639 94508060 Michael Hanselmann
  master = GetMasterNode()
640 94508060 Michael Hanselmann
641 94508060 Michael Hanselmann
  tmpfile = UploadFile(master['primary'], localpath)
642 94508060 Michael Hanselmann
  try:
643 94508060 Michael Hanselmann
    cmd = ['mv', tmpfile, constants.SSH_KNOWN_HOSTS_FILE]
644 94508060 Michael Hanselmann
    AssertEqual(StartSSH(master['primary'],
645 94508060 Michael Hanselmann
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
646 94508060 Michael Hanselmann
  except:
647 94508060 Michael Hanselmann
    cmd = ['rm', '-f', tmpfile]
648 94508060 Michael Hanselmann
    AssertEqual(StartSSH(master['primary'],
649 94508060 Michael Hanselmann
                         utils.ShellQuoteArgs(cmd)).wait(), 0)
650 94508060 Michael Hanselmann
    raise
651 94508060 Michael Hanselmann
652 94508060 Michael Hanselmann
# }}}
653 94508060 Michael Hanselmann
654 a8083063 Iustin Pop
# {{{ Main program
655 a8083063 Iustin Pop
if __name__ == '__main__':
656 a8083063 Iustin Pop
  # {{{ Option parsing
657 94508060 Michael Hanselmann
  parser = OptionParser(usage="%prog [options] <config-file> "
658 94508060 Michael Hanselmann
                              "<known-hosts-file>")
659 a8083063 Iustin Pop
  parser.add_option('--dry-run', dest='dry_run',
660 a8083063 Iustin Pop
      action="store_true",
661 a8083063 Iustin Pop
      help="Show what would be done")
662 a8083063 Iustin Pop
  parser.add_option('--yes-do-it', dest='yes_do_it',
663 a8083063 Iustin Pop
      action="store_true",
664 a8083063 Iustin Pop
      help="Really execute the tests")
665 a8083063 Iustin Pop
  (options, args) = parser.parse_args()
666 a8083063 Iustin Pop
  # }}}
667 a8083063 Iustin Pop
668 94508060 Michael Hanselmann
  if len(args) == 2:
669 94508060 Michael Hanselmann
    (config_file, known_hosts_file) = args
670 a8083063 Iustin Pop
  else:
671 94508060 Michael Hanselmann
    parser.error("Not enough arguments.")
672 a8083063 Iustin Pop
673 a8083063 Iustin Pop
  if not options.yes_do_it:
674 a8083063 Iustin Pop
    print ("Executing this script irreversibly destroys any Ganeti\n"
675 a8083063 Iustin Pop
           "configuration on all nodes involved. If you really want\n"
676 a8083063 Iustin Pop
           "to start testing, supply the --yes-do-it option.")
677 a8083063 Iustin Pop
    sys.exit(1)
678 a8083063 Iustin Pop
679 a8083063 Iustin Pop
  f = open(config_file, 'r')
680 a8083063 Iustin Pop
  try:
681 a8083063 Iustin Pop
    cfg = yaml.load(f.read())
682 a8083063 Iustin Pop
  finally:
683 a8083063 Iustin Pop
    f.close()
684 a8083063 Iustin Pop
685 a8083063 Iustin Pop
  RunTest(TestConfig)
686 a8083063 Iustin Pop
687 94508060 Michael Hanselmann
  RunTest(TestUploadKnownHostsFile, known_hosts_file)
688 94508060 Michael Hanselmann
689 a8083063 Iustin Pop
  if TestEnabled('env'):
690 a8083063 Iustin Pop
    RunTest(TestSshConnection)
691 a8083063 Iustin Pop
    RunTest(TestIcmpPing)
692 a8083063 Iustin Pop
    RunTest(TestGanetiCommands)
693 a8083063 Iustin Pop
694 a8083063 Iustin Pop
  RunTest(TestClusterInit)
695 a8083063 Iustin Pop
696 180bdd1f Michael Hanselmann
  RunTest(TestNodeAddAll)
697 180bdd1f Michael Hanselmann
698 a8083063 Iustin Pop
  if TestEnabled('cluster-verify'):
699 a8083063 Iustin Pop
    RunTest(TestClusterVerify)
700 e9e35aaa Michael Hanselmann
701 e9e35aaa Michael Hanselmann
  if TestEnabled('cluster-info'):
702 a8083063 Iustin Pop
    RunTest(TestClusterInfo)
703 a8083063 Iustin Pop
704 180bdd1f Michael Hanselmann
  if TestEnabled('cluster-copyfile'):
705 180bdd1f Michael Hanselmann
    RunTest(TestClusterCopyfile)
706 a8083063 Iustin Pop
707 e9e35aaa Michael Hanselmann
  if TestEnabled('node-info'):
708 e9e35aaa Michael Hanselmann
    RunTest(TestNodeInfo)
709 e9e35aaa Michael Hanselmann
710 a8083063 Iustin Pop
  if TestEnabled('cluster-burnin'):
711 a8083063 Iustin Pop
    RunTest(TestClusterBurnin)
712 a8083063 Iustin Pop
713 a8083063 Iustin Pop
  if TestEnabled('cluster-master-failover'):
714 a8083063 Iustin Pop
    RunTest(TestClusterMasterFailover)
715 a8083063 Iustin Pop
716 a8083063 Iustin Pop
  node = AcquireNode()
717 a8083063 Iustin Pop
  try:
718 a8083063 Iustin Pop
    if TestEnabled('instance-add-plain-disk'):
719 a8083063 Iustin Pop
      instance = RunTest(TestInstanceAddWithPlainDisk, node)
720 a8083063 Iustin Pop
      RunTest(TestInstanceShutdown, instance)
721 a8083063 Iustin Pop
      RunTest(TestInstanceStartup, instance)
722 a8083063 Iustin Pop
723 e9e35aaa Michael Hanselmann
      if TestEnabled('instance-info'):
724 e9e35aaa Michael Hanselmann
        RunTest(TestInstanceInfo, instance)
725 e9e35aaa Michael Hanselmann
726 a8083063 Iustin Pop
      if TestEnabled('instance-automatic-restart'):
727 a8083063 Iustin Pop
        RunTest(TestInstanceAutomaticRestart, node, instance)
728 a8083063 Iustin Pop
729 a8083063 Iustin Pop
      if TestEnabled('instance-consecutive-failures'):
730 a8083063 Iustin Pop
        RunTest(TestInstanceConsecutiveFailures, node, instance)
731 a8083063 Iustin Pop
732 a8083063 Iustin Pop
      RunTest(TestInstanceRemove, instance)
733 a8083063 Iustin Pop
      del instance
734 a8083063 Iustin Pop
735 a8083063 Iustin Pop
    if TestEnabled('instance-add-local-mirror-disk'):
736 a8083063 Iustin Pop
      instance = RunTest(TestInstanceAddWithLocalMirrorDisk, node)
737 a8083063 Iustin Pop
      RunTest(TestInstanceShutdown, instance)
738 a8083063 Iustin Pop
      RunTest(TestInstanceStartup, instance)
739 e9e35aaa Michael Hanselmann
740 e9e35aaa Michael Hanselmann
      if TestEnabled('instance-info'):
741 e9e35aaa Michael Hanselmann
        RunTest(TestInstanceInfo, instance)
742 e9e35aaa Michael Hanselmann
743 a8083063 Iustin Pop
      RunTest(TestInstanceRemove, instance)
744 a8083063 Iustin Pop
      del instance
745 a8083063 Iustin Pop
746 a8083063 Iustin Pop
    if TestEnabled('instance-add-remote-raid-disk'):
747 a8083063 Iustin Pop
      node2 = AcquireNode(exclude=node)
748 a8083063 Iustin Pop
      try:
749 a8083063 Iustin Pop
        instance = RunTest(TestInstanceAddWithRemoteRaidDisk, node, node2)
750 a8083063 Iustin Pop
        RunTest(TestInstanceShutdown, instance)
751 a8083063 Iustin Pop
        RunTest(TestInstanceStartup, instance)
752 a8083063 Iustin Pop
753 e9e35aaa Michael Hanselmann
        if TestEnabled('instance-info'):
754 e9e35aaa Michael Hanselmann
          RunTest(TestInstanceInfo, instance)
755 e9e35aaa Michael Hanselmann
756 a8083063 Iustin Pop
        if TestEnabled('instance-failover'):
757 a8083063 Iustin Pop
          RunTest(TestInstanceFailover, instance)
758 a8083063 Iustin Pop
759 a8083063 Iustin Pop
        RunTest(TestInstanceRemove, instance)
760 a8083063 Iustin Pop
        del instance
761 a8083063 Iustin Pop
      finally:
762 a8083063 Iustin Pop
        ReleaseNode(node2)
763 a8083063 Iustin Pop
764 a8083063 Iustin Pop
  finally:
765 a8083063 Iustin Pop
    ReleaseNode(node)
766 a8083063 Iustin Pop
767 a8083063 Iustin Pop
  RunTest(TestNodeRemoveAll)
768 a8083063 Iustin Pop
769 a8083063 Iustin Pop
  if TestEnabled('cluster-destroy'):
770 a8083063 Iustin Pop
    RunTest(TestClusterDestroy)
771 a8083063 Iustin Pop
# }}}
772 a8083063 Iustin Pop
773 a8083063 Iustin Pop
# vim: foldmethod=marker :