Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 1e82a86b

History | View | Annotate | Download (36.9 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 01b69ec5 Michael Hanselmann
# Copyright (C) 2006, 2007 Google Inc.
5 01b69ec5 Michael Hanselmann
#
6 01b69ec5 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 01b69ec5 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 01b69ec5 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 01b69ec5 Michael Hanselmann
# (at your option) any later version.
10 01b69ec5 Michael Hanselmann
#
11 01b69ec5 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 01b69ec5 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 01b69ec5 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 01b69ec5 Michael Hanselmann
# General Public License for more details.
15 01b69ec5 Michael Hanselmann
#
16 01b69ec5 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 01b69ec5 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 01b69ec5 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 01b69ec5 Michael Hanselmann
# 02110-1301, USA.
20 01b69ec5 Michael Hanselmann
21 01b69ec5 Michael Hanselmann
22 01b69ec5 Michael Hanselmann
"""Burnin program
23 01b69ec5 Michael Hanselmann
24 01b69ec5 Michael Hanselmann
"""
25 175f44c2 Iustin Pop
26 a8083063 Iustin Pop
import sys
27 a8083063 Iustin Pop
import optparse
28 e2212007 Iustin Pop
import time
29 5178f1bc Iustin Pop
import socket
30 5dc626fd Iustin Pop
import urllib
31 175f44c2 Iustin Pop
from itertools import izip, islice, cycle
32 21546b1c Iustin Pop
from cStringIO import StringIO
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti import opcodes
35 a8083063 Iustin Pop
from ganeti import constants
36 a8083063 Iustin Pop
from ganeti import cli
37 9f13fc7a Iustin Pop
from ganeti import errors
38 9f13fc7a Iustin Pop
from ganeti import utils
39 a619a1dd Guido Trotter
40 a619a1dd Guido Trotter
from ganeti.confd import client as confd_client
41 a8083063 Iustin Pop
42 01b69ec5 Michael Hanselmann
43 9f13fc7a Iustin Pop
USAGE = ("\tburnin -o OS_NAME [options...] instance_name ...")
44 a8083063 Iustin Pop
45 73ff3118 Iustin Pop
MAX_RETRIES = 3
46 1b334175 Iustin Pop
LOG_HEADERS = {
47 1b334175 Iustin Pop
  0: "- ",
48 1b334175 Iustin Pop
  1: "* ",
49 1b334175 Iustin Pop
  2: ""
50 1b334175 Iustin Pop
  }
51 01b69ec5 Michael Hanselmann
52 5178f1bc Iustin Pop
class InstanceDown(Exception):
53 5178f1bc Iustin Pop
  """The checked instance was not up"""
54 5178f1bc Iustin Pop
55 5178f1bc Iustin Pop
56 73ff3118 Iustin Pop
class BurninFailure(Exception):
57 73ff3118 Iustin Pop
  """Failure detected during burning"""
58 73ff3118 Iustin Pop
59 73ff3118 Iustin Pop
60 a8083063 Iustin Pop
def Usage():
61 a8083063 Iustin Pop
  """Shows program usage information and exits the program."""
62 a8083063 Iustin Pop
63 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
64 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
65 a8083063 Iustin Pop
  sys.exit(2)
66 a8083063 Iustin Pop
67 01b69ec5 Michael Hanselmann
68 1b334175 Iustin Pop
def Log(msg, *args, **kwargs):
69 3ecf6786 Iustin Pop
  """Simple function that prints out its argument.
70 3ecf6786 Iustin Pop
71 3ecf6786 Iustin Pop
  """
72 1b334175 Iustin Pop
  if args:
73 1b334175 Iustin Pop
    msg = msg % args
74 1b334175 Iustin Pop
  indent = kwargs.get('indent', 0)
75 836d59d7 Iustin Pop
  sys.stdout.write("%*s%s%s\n" % (2*indent, "",
76 1b334175 Iustin Pop
                                  LOG_HEADERS.get(indent, "  "), msg))
77 84cc52ab Michael Hanselmann
  sys.stdout.flush()
78 a8083063 Iustin Pop
79 1b334175 Iustin Pop
80 836d59d7 Iustin Pop
def Err(msg, exit_code=1):
81 836d59d7 Iustin Pop
  """Simple error logging that prints to stderr.
82 836d59d7 Iustin Pop
83 836d59d7 Iustin Pop
  """
84 836d59d7 Iustin Pop
  sys.stderr.write(msg + "\n")
85 836d59d7 Iustin Pop
  sys.stderr.flush()
86 836d59d7 Iustin Pop
  sys.exit(exit_code)
87 01b69ec5 Michael Hanselmann
88 5dc626fd Iustin Pop
89 5dc626fd Iustin Pop
class SimpleOpener(urllib.FancyURLopener):
90 5dc626fd Iustin Pop
  """A simple url opener"""
91 7260cfbe Iustin Pop
  # pylint: disable-msg=W0221
92 5dc626fd Iustin Pop
93 7260cfbe Iustin Pop
  def prompt_user_passwd(self, host, realm, clear_cache=0):
94 5dc626fd Iustin Pop
    """No-interaction version of prompt_user_passwd."""
95 2d54e29c Iustin Pop
    # we follow parent class' API
96 2d54e29c Iustin Pop
    # pylint: disable-msg=W0613
97 5dc626fd Iustin Pop
    return None, None
98 5dc626fd Iustin Pop
99 5dc626fd Iustin Pop
  def http_error_default(self, url, fp, errcode, errmsg, headers):
100 5dc626fd Iustin Pop
    """Custom error handling"""
101 5dc626fd Iustin Pop
    # make sure sockets are not left in CLOSE_WAIT, this is similar
102 5dc626fd Iustin Pop
    # but with a different exception to the BasicURLOpener class
103 5dc626fd Iustin Pop
    _ = fp.read() # throw away data
104 5dc626fd Iustin Pop
    fp.close()
105 5dc626fd Iustin Pop
    raise InstanceDown("HTTP error returned: code %s, msg %s" %
106 5dc626fd Iustin Pop
                       (errcode, errmsg))
107 5dc626fd Iustin Pop
108 5dc626fd Iustin Pop
109 10eb54fb Michael Hanselmann
OPTIONS = [
110 10eb54fb Michael Hanselmann
  cli.cli_option("-o", "--os", dest="os", default=None,
111 10eb54fb Michael Hanselmann
                 help="OS to use during burnin",
112 a52ba89d Michael Hanselmann
                 metavar="<OS>",
113 a52ba89d Michael Hanselmann
                 completion_suggest=cli.OPT_COMPL_ONE_OS),
114 10eb54fb Michael Hanselmann
  cli.cli_option("--disk-size", dest="disk_size",
115 10eb54fb Michael Hanselmann
                 help="Disk size (determines disk count)",
116 10eb54fb Michael Hanselmann
                 default="128m", type="string", metavar="<size,size,...>",
117 10eb54fb Michael Hanselmann
                 completion_suggest=("128M 512M 1G 4G 1G,256M"
118 10eb54fb Michael Hanselmann
                                     " 4G,1G,1G 10G").split()),
119 10eb54fb Michael Hanselmann
  cli.cli_option("--disk-growth", dest="disk_growth", help="Disk growth",
120 10eb54fb Michael Hanselmann
                 default="128m", type="string", metavar="<size,size,...>"),
121 10eb54fb Michael Hanselmann
  cli.cli_option("--mem-size", dest="mem_size", help="Memory size",
122 10eb54fb Michael Hanselmann
                 default=128, type="unit", metavar="<size>",
123 10eb54fb Michael Hanselmann
                 completion_suggest=("128M 256M 512M 1G 4G 8G"
124 10eb54fb Michael Hanselmann
                                     " 12G 16G").split()),
125 265e6244 Iustin Pop
  cli.DEBUG_OPT,
126 9cdb9578 Iustin Pop
  cli.VERBOSE_OPT,
127 544ca43b Iustin Pop
  cli.NOIPCHECK_OPT,
128 544ca43b Iustin Pop
  cli.NONAMECHECK_OPT,
129 7ea7bcf6 Iustin Pop
  cli.EARLY_RELEASE_OPT,
130 10eb54fb Michael Hanselmann
  cli.cli_option("--no-replace1", dest="do_replace1",
131 10eb54fb Michael Hanselmann
                 help="Skip disk replacement with the same secondary",
132 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
133 10eb54fb Michael Hanselmann
  cli.cli_option("--no-replace2", dest="do_replace2",
134 10eb54fb Michael Hanselmann
                 help="Skip disk replacement with a different secondary",
135 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
136 10eb54fb Michael Hanselmann
  cli.cli_option("--no-failover", dest="do_failover",
137 10eb54fb Michael Hanselmann
                 help="Skip instance failovers", action="store_false",
138 10eb54fb Michael Hanselmann
                 default=True),
139 10eb54fb Michael Hanselmann
  cli.cli_option("--no-migrate", dest="do_migrate",
140 10eb54fb Michael Hanselmann
                 help="Skip instance live migration",
141 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
142 5b9107ff Iustin Pop
  cli.cli_option("--no-move", dest="do_move",
143 5b9107ff Iustin Pop
                 help="Skip instance moves", action="store_false",
144 5b9107ff Iustin Pop
                 default=True),
145 10eb54fb Michael Hanselmann
  cli.cli_option("--no-importexport", dest="do_importexport",
146 10eb54fb Michael Hanselmann
                 help="Skip instance export/import", action="store_false",
147 10eb54fb Michael Hanselmann
                 default=True),
148 10eb54fb Michael Hanselmann
  cli.cli_option("--no-startstop", dest="do_startstop",
149 10eb54fb Michael Hanselmann
                 help="Skip instance stop/start", action="store_false",
150 10eb54fb Michael Hanselmann
                 default=True),
151 10eb54fb Michael Hanselmann
  cli.cli_option("--no-reinstall", dest="do_reinstall",
152 10eb54fb Michael Hanselmann
                 help="Skip instance reinstall", action="store_false",
153 10eb54fb Michael Hanselmann
                 default=True),
154 10eb54fb Michael Hanselmann
  cli.cli_option("--no-reboot", dest="do_reboot",
155 10eb54fb Michael Hanselmann
                 help="Skip instance reboot", action="store_false",
156 10eb54fb Michael Hanselmann
                 default=True),
157 10eb54fb Michael Hanselmann
  cli.cli_option("--no-activate-disks", dest="do_activate_disks",
158 10eb54fb Michael Hanselmann
                 help="Skip disk activation/deactivation",
159 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
160 10eb54fb Michael Hanselmann
  cli.cli_option("--no-add-disks", dest="do_addremove_disks",
161 10eb54fb Michael Hanselmann
                 help="Skip disk addition/removal",
162 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
163 10eb54fb Michael Hanselmann
  cli.cli_option("--no-add-nics", dest="do_addremove_nics",
164 10eb54fb Michael Hanselmann
                 help="Skip NIC addition/removal",
165 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
166 10eb54fb Michael Hanselmann
  cli.cli_option("--no-nics", dest="nics",
167 10eb54fb Michael Hanselmann
                 help="No network interfaces", action="store_const",
168 10eb54fb Michael Hanselmann
                 const=[], default=[{}]),
169 a619a1dd Guido Trotter
  cli.cli_option("--no-confd", dest="do_confd_tests",
170 a619a1dd Guido Trotter
                 help="Skip confd queries",
171 a619a1dd Guido Trotter
                 action="store_false", default=True),
172 10eb54fb Michael Hanselmann
  cli.cli_option("--rename", dest="rename", default=None,
173 10eb54fb Michael Hanselmann
                 help=("Give one unused instance name which is taken"
174 10eb54fb Michael Hanselmann
                       " to start the renaming sequence"),
175 10eb54fb Michael Hanselmann
                 metavar="<instance_name>"),
176 10eb54fb Michael Hanselmann
  cli.cli_option("-t", "--disk-template", dest="disk_template",
177 10eb54fb Michael Hanselmann
                 choices=list(constants.DISK_TEMPLATES),
178 10eb54fb Michael Hanselmann
                 default=constants.DT_DRBD8,
179 10eb54fb Michael Hanselmann
                 help="Disk template (diskless, file, plain or drbd) [drbd]"),
180 10eb54fb Michael Hanselmann
  cli.cli_option("-n", "--nodes", dest="nodes", default="",
181 10eb54fb Michael Hanselmann
                 help=("Comma separated list of nodes to perform"
182 a52ba89d Michael Hanselmann
                       " the burnin on (defaults to all nodes)"),
183 a52ba89d Michael Hanselmann
                 completion_suggest=cli.OPT_COMPL_MANY_NODES),
184 10eb54fb Michael Hanselmann
  cli.cli_option("-I", "--iallocator", dest="iallocator",
185 10eb54fb Michael Hanselmann
                 default=None, type="string",
186 10eb54fb Michael Hanselmann
                 help=("Perform the allocation using an iallocator"
187 10eb54fb Michael Hanselmann
                       " instead of fixed node spread (node restrictions no"
188 10eb54fb Michael Hanselmann
                       " longer apply, therefore -n/--nodes must not be"
189 a52ba89d Michael Hanselmann
                       " used"),
190 a52ba89d Michael Hanselmann
                 completion_suggest=cli.OPT_COMPL_ONE_IALLOCATOR),
191 10eb54fb Michael Hanselmann
  cli.cli_option("-p", "--parallel", default=False, action="store_true",
192 10eb54fb Michael Hanselmann
                 dest="parallel",
193 10eb54fb Michael Hanselmann
                 help=("Enable parallelization of some operations in"
194 10eb54fb Michael Hanselmann
                       " order to speed burnin or to test granular locking")),
195 10eb54fb Michael Hanselmann
  cli.cli_option("--net-timeout", default=15, type="int",
196 10eb54fb Michael Hanselmann
                 dest="net_timeout",
197 10eb54fb Michael Hanselmann
                 help=("The instance check network timeout in seconds"
198 10eb54fb Michael Hanselmann
                       " (defaults to 15 seconds)"),
199 10eb54fb Michael Hanselmann
                 completion_suggest="15 60 300 900".split()),
200 10eb54fb Michael Hanselmann
  cli.cli_option("-C", "--http-check", default=False, action="store_true",
201 10eb54fb Michael Hanselmann
                 dest="http_check",
202 10eb54fb Michael Hanselmann
                 help=("Enable checking of instance status via http,"
203 10eb54fb Michael Hanselmann
                       " looking for /hostname.txt that should contain the"
204 10eb54fb Michael Hanselmann
                       " name of the instance")),
205 10eb54fb Michael Hanselmann
  cli.cli_option("-K", "--keep-instances", default=False,
206 10eb54fb Michael Hanselmann
                 action="store_true",
207 10eb54fb Michael Hanselmann
                 dest="keep_instances",
208 10eb54fb Michael Hanselmann
                 help=("Leave instances on the cluster after burnin,"
209 10eb54fb Michael Hanselmann
                       " for investigation in case of errors or simply"
210 10eb54fb Michael Hanselmann
                       " to use them")),
211 10eb54fb Michael Hanselmann
  ]
212 10eb54fb Michael Hanselmann
213 10eb54fb Michael Hanselmann
# Mainly used for bash completion
214 10eb54fb Michael Hanselmann
ARGUMENTS = [cli.ArgInstance(min=1)]
215 10eb54fb Michael Hanselmann
216 10eb54fb Michael Hanselmann
217 e7beaa02 Iustin Pop
def _DoCheckInstances(fn):
218 e7beaa02 Iustin Pop
  """Decorator for checking instances.
219 e7beaa02 Iustin Pop
220 e7beaa02 Iustin Pop
  """
221 e7beaa02 Iustin Pop
  def wrapper(self, *args, **kwargs):
222 e7beaa02 Iustin Pop
    val = fn(self, *args, **kwargs)
223 e7beaa02 Iustin Pop
    for instance in self.instances:
224 7260cfbe Iustin Pop
      self._CheckInstanceAlive(instance) # pylint: disable-msg=W0212
225 e7beaa02 Iustin Pop
    return val
226 e7beaa02 Iustin Pop
227 e7beaa02 Iustin Pop
  return wrapper
228 e7beaa02 Iustin Pop
229 e7beaa02 Iustin Pop
230 e7beaa02 Iustin Pop
def _DoBatch(retry):
231 e7beaa02 Iustin Pop
  """Decorator for possible batch operations.
232 e7beaa02 Iustin Pop
233 e7beaa02 Iustin Pop
  Must come after the _DoCheckInstances decorator (if any).
234 e7beaa02 Iustin Pop
235 e7beaa02 Iustin Pop
  @param retry: whether this is a retryable batch, will be
236 e7beaa02 Iustin Pop
      passed to StartBatch
237 e7beaa02 Iustin Pop
238 e7beaa02 Iustin Pop
  """
239 e7beaa02 Iustin Pop
  def wrap(fn):
240 e7beaa02 Iustin Pop
    def batched(self, *args, **kwargs):
241 e7beaa02 Iustin Pop
      self.StartBatch(retry)
242 e7beaa02 Iustin Pop
      val = fn(self, *args, **kwargs)
243 e7beaa02 Iustin Pop
      self.CommitQueue()
244 e7beaa02 Iustin Pop
      return val
245 e7beaa02 Iustin Pop
    return batched
246 e7beaa02 Iustin Pop
247 e7beaa02 Iustin Pop
  return wrap
248 e7beaa02 Iustin Pop
249 e7beaa02 Iustin Pop
250 175f44c2 Iustin Pop
class Burner(object):
251 175f44c2 Iustin Pop
  """Burner class."""
252 175f44c2 Iustin Pop
253 175f44c2 Iustin Pop
  def __init__(self):
254 175f44c2 Iustin Pop
    """Constructor."""
255 82d9caef Iustin Pop
    utils.SetupLogging(constants.LOG_BURNIN, debug=False, stderr_logging=True)
256 5dc626fd Iustin Pop
    self.url_opener = SimpleOpener()
257 21546b1c Iustin Pop
    self._feed_buf = StringIO()
258 175f44c2 Iustin Pop
    self.nodes = []
259 175f44c2 Iustin Pop
    self.instances = []
260 175f44c2 Iustin Pop
    self.to_rem = []
261 c723c163 Iustin Pop
    self.queued_ops = []
262 175f44c2 Iustin Pop
    self.opts = None
263 73ff3118 Iustin Pop
    self.queue_retry = False
264 73ff3118 Iustin Pop
    self.disk_count = self.disk_growth = self.disk_size = None
265 73ff3118 Iustin Pop
    self.hvp = self.bep = None
266 175f44c2 Iustin Pop
    self.ParseOptions()
267 320eda24 Iustin Pop
    self.cl = cli.GetClient()
268 175f44c2 Iustin Pop
    self.GetState()
269 175f44c2 Iustin Pop
270 21546b1c Iustin Pop
  def ClearFeedbackBuf(self):
271 21546b1c Iustin Pop
    """Clear the feedback buffer."""
272 21546b1c Iustin Pop
    self._feed_buf.truncate(0)
273 21546b1c Iustin Pop
274 21546b1c Iustin Pop
  def GetFeedbackBuf(self):
275 21546b1c Iustin Pop
    """Return the contents of the buffer."""
276 21546b1c Iustin Pop
    return self._feed_buf.getvalue()
277 21546b1c Iustin Pop
278 21546b1c Iustin Pop
  def Feedback(self, msg):
279 21546b1c Iustin Pop
    """Acumulate feedback in our buffer."""
280 88d31e5c Iustin Pop
    formatted_msg = "%s %s" % (time.ctime(utils.MergeTime(msg[0])), msg[2])
281 88d31e5c Iustin Pop
    self._feed_buf.write(formatted_msg + "\n")
282 d7b47a77 Iustin Pop
    if self.opts.verbose:
283 88d31e5c Iustin Pop
      Log(formatted_msg, indent=3)
284 21546b1c Iustin Pop
285 73ff3118 Iustin Pop
  def MaybeRetry(self, retry_count, msg, fn, *args):
286 73ff3118 Iustin Pop
    """Possibly retry a given function execution.
287 73ff3118 Iustin Pop
288 73ff3118 Iustin Pop
    @type retry_count: int
289 73ff3118 Iustin Pop
    @param retry_count: retry counter:
290 73ff3118 Iustin Pop
        - 0: non-retryable action
291 73ff3118 Iustin Pop
        - 1: last retry for a retryable action
292 73ff3118 Iustin Pop
        - MAX_RETRIES: original try for a retryable action
293 73ff3118 Iustin Pop
    @type msg: str
294 73ff3118 Iustin Pop
    @param msg: the kind of the operation
295 73ff3118 Iustin Pop
    @type fn: callable
296 73ff3118 Iustin Pop
    @param fn: the function to be called
297 73ff3118 Iustin Pop
298 73ff3118 Iustin Pop
    """
299 73ff3118 Iustin Pop
    try:
300 73ff3118 Iustin Pop
      val = fn(*args)
301 73ff3118 Iustin Pop
      if retry_count > 0 and retry_count < MAX_RETRIES:
302 1b334175 Iustin Pop
        Log("Idempotent %s succeeded after %d retries",
303 1b334175 Iustin Pop
            msg, MAX_RETRIES - retry_count)
304 73ff3118 Iustin Pop
      return val
305 7260cfbe Iustin Pop
    except Exception, err: # pylint: disable-msg=W0703
306 73ff3118 Iustin Pop
      if retry_count == 0:
307 1b334175 Iustin Pop
        Log("Non-idempotent %s failed, aborting", msg)
308 73ff3118 Iustin Pop
        raise
309 73ff3118 Iustin Pop
      elif retry_count == 1:
310 1b334175 Iustin Pop
        Log("Idempotent %s repeated failure, aborting", msg)
311 73ff3118 Iustin Pop
        raise
312 73ff3118 Iustin Pop
      else:
313 1b334175 Iustin Pop
        Log("Idempotent %s failed, retry #%d/%d: %s",
314 1b334175 Iustin Pop
            msg, MAX_RETRIES - retry_count + 1, MAX_RETRIES, err)
315 73ff3118 Iustin Pop
        self.MaybeRetry(retry_count - 1, msg, fn, *args)
316 73ff3118 Iustin Pop
317 265e6244 Iustin Pop
  def _SetDebug(self, ops):
318 265e6244 Iustin Pop
    """Set the debug value on the given opcodes"""
319 265e6244 Iustin Pop
    for op in ops:
320 265e6244 Iustin Pop
      op.debug_level = self.opts.debug
321 265e6244 Iustin Pop
322 73ff3118 Iustin Pop
  def _ExecOp(self, *ops):
323 c723c163 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
324 c723c163 Iustin Pop
325 c723c163 Iustin Pop
    @result: if only opcode has been passed, we return its result;
326 c723c163 Iustin Pop
        otherwise we return the list of results
327 c723c163 Iustin Pop
328 c723c163 Iustin Pop
    """
329 c723c163 Iustin Pop
    job_id = cli.SendJob(ops, cl=self.cl)
330 c723c163 Iustin Pop
    results = cli.PollJob(job_id, cl=self.cl, feedback_fn=self.Feedback)
331 c723c163 Iustin Pop
    if len(ops) == 1:
332 c723c163 Iustin Pop
      return results[0]
333 c723c163 Iustin Pop
    else:
334 c723c163 Iustin Pop
      return results
335 c723c163 Iustin Pop
336 73ff3118 Iustin Pop
  def ExecOp(self, retry, *ops):
337 73ff3118 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
338 73ff3118 Iustin Pop
339 73ff3118 Iustin Pop
    @result: if only opcode has been passed, we return its result;
340 73ff3118 Iustin Pop
        otherwise we return the list of results
341 73ff3118 Iustin Pop
342 73ff3118 Iustin Pop
    """
343 73ff3118 Iustin Pop
    if retry:
344 73ff3118 Iustin Pop
      rval = MAX_RETRIES
345 73ff3118 Iustin Pop
    else:
346 73ff3118 Iustin Pop
      rval = 0
347 265e6244 Iustin Pop
    self._SetDebug(ops)
348 73ff3118 Iustin Pop
    return self.MaybeRetry(rval, "opcode", self._ExecOp, *ops)
349 73ff3118 Iustin Pop
350 2c035435 Guido Trotter
  def ExecOrQueue(self, name, ops, post_process=None):
351 21546b1c Iustin Pop
    """Execute an opcode and manage the exec buffer."""
352 c723c163 Iustin Pop
    if self.opts.parallel:
353 265e6244 Iustin Pop
      self._SetDebug(ops)
354 2c035435 Guido Trotter
      self.queued_ops.append((ops, name, post_process))
355 c723c163 Iustin Pop
    else:
356 2c035435 Guido Trotter
      val = self.ExecOp(self.queue_retry, *ops) # pylint: disable-msg=W0142
357 2c035435 Guido Trotter
      if post_process is not None:
358 2c035435 Guido Trotter
        post_process()
359 2c035435 Guido Trotter
      return val
360 73ff3118 Iustin Pop
361 73ff3118 Iustin Pop
  def StartBatch(self, retry):
362 73ff3118 Iustin Pop
    """Start a new batch of jobs.
363 73ff3118 Iustin Pop
364 73ff3118 Iustin Pop
    @param retry: whether this is a retryable batch
365 73ff3118 Iustin Pop
366 73ff3118 Iustin Pop
    """
367 73ff3118 Iustin Pop
    self.queued_ops = []
368 73ff3118 Iustin Pop
    self.queue_retry = retry
369 c723c163 Iustin Pop
370 c723c163 Iustin Pop
  def CommitQueue(self):
371 c723c163 Iustin Pop
    """Execute all submitted opcodes in case of parallel burnin"""
372 c723c163 Iustin Pop
    if not self.opts.parallel:
373 c723c163 Iustin Pop
      return
374 c723c163 Iustin Pop
375 73ff3118 Iustin Pop
    if self.queue_retry:
376 73ff3118 Iustin Pop
      rval = MAX_RETRIES
377 73ff3118 Iustin Pop
    else:
378 73ff3118 Iustin Pop
      rval = 0
379 73ff3118 Iustin Pop
380 c723c163 Iustin Pop
    try:
381 73ff3118 Iustin Pop
      results = self.MaybeRetry(rval, "jobset", self.ExecJobSet,
382 73ff3118 Iustin Pop
                                self.queued_ops)
383 c723c163 Iustin Pop
    finally:
384 c723c163 Iustin Pop
      self.queued_ops = []
385 c723c163 Iustin Pop
    return results
386 ec5c88dc Iustin Pop
387 ec5c88dc Iustin Pop
  def ExecJobSet(self, jobs):
388 ec5c88dc Iustin Pop
    """Execute a set of jobs and return once all are done.
389 ec5c88dc Iustin Pop
390 ec5c88dc Iustin Pop
    The method will return the list of results, if all jobs are
391 c723c163 Iustin Pop
    successful. Otherwise, OpExecError will be raised from within
392 ec5c88dc Iustin Pop
    cli.py.
393 ec5c88dc Iustin Pop
394 ec5c88dc Iustin Pop
    """
395 ec5c88dc Iustin Pop
    self.ClearFeedbackBuf()
396 14947dbc Iustin Pop
    jex = cli.JobExecutor(cl=self.cl, feedback_fn=self.Feedback)
397 2c035435 Guido Trotter
    for ops, name, _ in jobs:
398 14947dbc Iustin Pop
      jex.QueueJob(name, *ops) # pylint: disable-msg=W0142
399 14947dbc Iustin Pop
    try:
400 14947dbc Iustin Pop
      results = jex.GetResults()
401 14947dbc Iustin Pop
    except Exception, err: # pylint: disable-msg=W0703
402 14947dbc Iustin Pop
      Log("Jobs failed: %s", err)
403 73ff3118 Iustin Pop
      raise BurninFailure()
404 14947dbc Iustin Pop
405 2c035435 Guido Trotter
    fail = False
406 2c035435 Guido Trotter
    val = []
407 2c035435 Guido Trotter
    for (_, name, post_process), (success, result) in zip(jobs, results):
408 2c035435 Guido Trotter
      if success:
409 2c035435 Guido Trotter
        if post_process:
410 2c035435 Guido Trotter
          try:
411 2c035435 Guido Trotter
            post_process()
412 2c035435 Guido Trotter
          except Exception, err: # pylint: disable-msg=W0703
413 2c035435 Guido Trotter
            Log("Post process call for job %s failed: %s", name, err)
414 2c035435 Guido Trotter
            fail = True
415 2c035435 Guido Trotter
        val.append(result)
416 2c035435 Guido Trotter
      else:
417 2c035435 Guido Trotter
        fail = True
418 2c035435 Guido Trotter
419 2c035435 Guido Trotter
    if fail:
420 14947dbc Iustin Pop
      raise BurninFailure()
421 14947dbc Iustin Pop
422 2c035435 Guido Trotter
    return val
423 21546b1c Iustin Pop
424 175f44c2 Iustin Pop
  def ParseOptions(self):
425 175f44c2 Iustin Pop
    """Parses the command line options.
426 175f44c2 Iustin Pop
427 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
428 175f44c2 Iustin Pop
    program.
429 175f44c2 Iustin Pop
430 175f44c2 Iustin Pop
    """
431 175f44c2 Iustin Pop
    parser = optparse.OptionParser(usage="\n%s" % USAGE,
432 10eb54fb Michael Hanselmann
                                   version=("%%prog (ganeti) %s" %
433 10eb54fb Michael Hanselmann
                                            constants.RELEASE_VERSION),
434 10eb54fb Michael Hanselmann
                                   option_list=OPTIONS)
435 175f44c2 Iustin Pop
436 175f44c2 Iustin Pop
    options, args = parser.parse_args()
437 175f44c2 Iustin Pop
    if len(args) < 1 or options.os is None:
438 175f44c2 Iustin Pop
      Usage()
439 175f44c2 Iustin Pop
440 f9193417 Iustin Pop
    supported_disk_templates = (constants.DT_DISKLESS,
441 2f505cb5 Manuel Franceschini
                                constants.DT_FILE,
442 f9193417 Iustin Pop
                                constants.DT_PLAIN,
443 12c3449a Michael Hanselmann
                                constants.DT_DRBD8)
444 12c3449a Michael Hanselmann
    if options.disk_template not in supported_disk_templates:
445 836d59d7 Iustin Pop
      Err("Unknown disk template '%s'" % options.disk_template)
446 175f44c2 Iustin Pop
447 b518a14a Iustin Pop
    if options.disk_template == constants.DT_DISKLESS:
448 b518a14a Iustin Pop
      disk_size = disk_growth = []
449 5178f1bc Iustin Pop
      options.do_addremove_disks = False
450 b518a14a Iustin Pop
    else:
451 b518a14a Iustin Pop
      disk_size = [utils.ParseUnit(v) for v in options.disk_size.split(",")]
452 b518a14a Iustin Pop
      disk_growth = [utils.ParseUnit(v)
453 b518a14a Iustin Pop
                     for v in options.disk_growth.split(",")]
454 b518a14a Iustin Pop
      if len(disk_growth) != len(disk_size):
455 836d59d7 Iustin Pop
        Err("Wrong disk sizes/growth combination")
456 08db7c5c Iustin Pop
    if ((disk_size and options.disk_template == constants.DT_DISKLESS) or
457 08db7c5c Iustin Pop
        (not disk_size and options.disk_template != constants.DT_DISKLESS)):
458 836d59d7 Iustin Pop
      Err("Wrong disk count/disk template combination")
459 08db7c5c Iustin Pop
460 08db7c5c Iustin Pop
    self.disk_size = disk_size
461 08db7c5c Iustin Pop
    self.disk_growth = disk_growth
462 08db7c5c Iustin Pop
    self.disk_count = len(disk_size)
463 08db7c5c Iustin Pop
464 b91bde14 Iustin Pop
    if options.nodes and options.iallocator:
465 836d59d7 Iustin Pop
      Err("Give either the nodes option or the iallocator option, not both")
466 b91bde14 Iustin Pop
467 544ca43b Iustin Pop
    if options.http_check and not options.name_check:
468 544ca43b Iustin Pop
      Err("Can't enable HTTP checks without name checks")
469 544ca43b Iustin Pop
470 175f44c2 Iustin Pop
    self.opts = options
471 175f44c2 Iustin Pop
    self.instances = args
472 338e51e8 Iustin Pop
    self.bep = {
473 338e51e8 Iustin Pop
      constants.BE_MEMORY: options.mem_size,
474 338e51e8 Iustin Pop
      constants.BE_VCPUS: 1,
475 338e51e8 Iustin Pop
      }
476 338e51e8 Iustin Pop
    self.hvp = {}
477 175f44c2 Iustin Pop
478 5178f1bc Iustin Pop
    socket.setdefaulttimeout(options.net_timeout)
479 5178f1bc Iustin Pop
480 175f44c2 Iustin Pop
  def GetState(self):
481 be0636e3 Guido Trotter
    """Read the cluster state from the master daemon."""
482 175f44c2 Iustin Pop
    if self.opts.nodes:
483 175f44c2 Iustin Pop
      names = self.opts.nodes.split(",")
484 175f44c2 Iustin Pop
    else:
485 175f44c2 Iustin Pop
      names = []
486 175f44c2 Iustin Pop
    try:
487 e8d47209 Iustin Pop
      op = opcodes.OpQueryNodes(output_fields=["name", "offline", "drained"],
488 ec79568d Iustin Pop
                                names=names, use_locking=True)
489 73ff3118 Iustin Pop
      result = self.ExecOp(True, op)
490 175f44c2 Iustin Pop
    except errors.GenericError, err:
491 175f44c2 Iustin Pop
      err_code, msg = cli.FormatError(err)
492 836d59d7 Iustin Pop
      Err(msg, exit_code=err_code)
493 e8d47209 Iustin Pop
    self.nodes = [data[0] for data in result if not (data[1] or data[2])]
494 175f44c2 Iustin Pop
495 e3ac208c Guido Trotter
    op_diagnose = opcodes.OpDiagnoseOS(output_fields=["name", "valid",
496 e3ac208c Guido Trotter
                                                      "variants"], names=[])
497 e3ac208c Guido Trotter
    result = self.ExecOp(True, op_diagnose)
498 175f44c2 Iustin Pop
499 175f44c2 Iustin Pop
    if not result:
500 836d59d7 Iustin Pop
      Err("Can't get the OS list")
501 175f44c2 Iustin Pop
502 e3ac208c Guido Trotter
    found = False
503 e3ac208c Guido Trotter
    for (name, valid, variants) in result:
504 e3ac208c Guido Trotter
      if valid and self.opts.os in cli.CalculateOSNames(name, variants):
505 e3ac208c Guido Trotter
        found = True
506 e3ac208c Guido Trotter
        break
507 175f44c2 Iustin Pop
508 e3ac208c Guido Trotter
    if not found:
509 836d59d7 Iustin Pop
      Err("OS '%s' not found" % self.opts.os)
510 175f44c2 Iustin Pop
511 be0636e3 Guido Trotter
    cluster_info = self.cl.QueryClusterInfo()
512 be0636e3 Guido Trotter
    self.cluster_info = cluster_info
513 be0636e3 Guido Trotter
    if not self.cluster_info:
514 be0636e3 Guido Trotter
      Err("Can't get cluster info")
515 be0636e3 Guido Trotter
516 be0636e3 Guido Trotter
    default_nic_params = self.cluster_info["nicparams"][constants.PP_DEFAULT]
517 be0636e3 Guido Trotter
    self.cluster_default_nicparams = default_nic_params
518 be0636e3 Guido Trotter
519 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
520 c70481ab Iustin Pop
  @_DoBatch(False)
521 c723c163 Iustin Pop
  def BurnCreateInstances(self):
522 175f44c2 Iustin Pop
    """Create the given instances.
523 175f44c2 Iustin Pop
524 175f44c2 Iustin Pop
    """
525 175f44c2 Iustin Pop
    self.to_rem = []
526 175f44c2 Iustin Pop
    mytor = izip(cycle(self.nodes),
527 175f44c2 Iustin Pop
                 islice(cycle(self.nodes), 1, None),
528 175f44c2 Iustin Pop
                 self.instances)
529 338e51e8 Iustin Pop
530 836d59d7 Iustin Pop
    Log("Creating instances")
531 175f44c2 Iustin Pop
    for pnode, snode, instance in mytor:
532 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
533 b91bde14 Iustin Pop
      if self.opts.iallocator:
534 b91bde14 Iustin Pop
        pnode = snode = None
535 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
536 6d54548e Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
537 6d54548e Guido Trotter
        snode = None
538 836d59d7 Iustin Pop
        msg = "on %s" % pnode
539 6d54548e Guido Trotter
      else:
540 836d59d7 Iustin Pop
        msg = "on %s, %s" % (pnode, snode)
541 836d59d7 Iustin Pop
542 836d59d7 Iustin Pop
      Log(msg, indent=2)
543 6d54548e Guido Trotter
544 175f44c2 Iustin Pop
      op = opcodes.OpCreateInstance(instance_name=instance,
545 08db7c5c Iustin Pop
                                    disks = [ {"size": size}
546 08db7c5c Iustin Pop
                                              for size in self.disk_size],
547 175f44c2 Iustin Pop
                                    disk_template=self.opts.disk_template,
548 b518a14a Iustin Pop
                                    nics=self.opts.nics,
549 a8083063 Iustin Pop
                                    mode=constants.INSTANCE_CREATE,
550 175f44c2 Iustin Pop
                                    os_type=self.opts.os,
551 175f44c2 Iustin Pop
                                    pnode=pnode,
552 175f44c2 Iustin Pop
                                    snode=snode,
553 a8083063 Iustin Pop
                                    start=True,
554 544ca43b Iustin Pop
                                    ip_check=self.opts.ip_check,
555 544ca43b Iustin Pop
                                    name_check=self.opts.name_check,
556 4501af56 Iustin Pop
                                    wait_for_sync=True,
557 2f505cb5 Manuel Franceschini
                                    file_driver="loop",
558 b91bde14 Iustin Pop
                                    file_storage_dir=None,
559 6e2dc934 Alexander Schreiber
                                    iallocator=self.opts.iallocator,
560 338e51e8 Iustin Pop
                                    beparams=self.bep,
561 338e51e8 Iustin Pop
                                    hvparams=self.hvp,
562 338e51e8 Iustin Pop
                                    )
563 1e82a86b Guido Trotter
      remove_instance = lambda name: lambda: self.to_rem.append(name)
564 1e82a86b Guido Trotter
      self.ExecOrQueue(instance, [op], post_process=remove_instance(instance))
565 c723c163 Iustin Pop
566 c70481ab Iustin Pop
  @_DoBatch(False)
567 c723c163 Iustin Pop
  def BurnGrowDisks(self):
568 659712c8 Iustin Pop
    """Grow both the os and the swap disks by the requested amount, if any."""
569 836d59d7 Iustin Pop
    Log("Growing disks")
570 659712c8 Iustin Pop
    for instance in self.instances:
571 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
572 08db7c5c Iustin Pop
      for idx, growth in enumerate(self.disk_growth):
573 659712c8 Iustin Pop
        if growth > 0:
574 08db7c5c Iustin Pop
          op = opcodes.OpGrowDisk(instance_name=instance, disk=idx,
575 6605411d Iustin Pop
                                  amount=growth, wait_for_sync=True)
576 1b334175 Iustin Pop
          Log("increase disk/%s by %s MB", idx, growth, indent=2)
577 b05f29a6 Guido Trotter
          self.ExecOrQueue(instance, [op])
578 659712c8 Iustin Pop
579 c70481ab Iustin Pop
  @_DoBatch(True)
580 c723c163 Iustin Pop
  def BurnReplaceDisks1D8(self):
581 175f44c2 Iustin Pop
    """Replace disks on primary and secondary for drbd8."""
582 836d59d7 Iustin Pop
    Log("Replacing disks on the same nodes")
583 175f44c2 Iustin Pop
    for instance in self.instances:
584 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
585 c723c163 Iustin Pop
      ops = []
586 175f44c2 Iustin Pop
      for mode in constants.REPLACE_DISK_SEC, constants.REPLACE_DISK_PRI:
587 175f44c2 Iustin Pop
        op = opcodes.OpReplaceDisks(instance_name=instance,
588 175f44c2 Iustin Pop
                                    mode=mode,
589 7ea7bcf6 Iustin Pop
                                    disks=[i for i in range(self.disk_count)],
590 7ea7bcf6 Iustin Pop
                                    early_release=self.opts.early_release)
591 1b334175 Iustin Pop
        Log("run %s", mode, indent=2)
592 c723c163 Iustin Pop
        ops.append(op)
593 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, ops)
594 175f44c2 Iustin Pop
595 c70481ab Iustin Pop
  @_DoBatch(True)
596 c723c163 Iustin Pop
  def BurnReplaceDisks2(self):
597 175f44c2 Iustin Pop
    """Replace secondary node."""
598 836d59d7 Iustin Pop
    Log("Changing the secondary node")
599 cfacfd6e Iustin Pop
    mode = constants.REPLACE_DISK_CHG
600 175f44c2 Iustin Pop
601 175f44c2 Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 2, None),
602 175f44c2 Iustin Pop
                 self.instances)
603 175f44c2 Iustin Pop
    for tnode, instance in mytor:
604 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
605 b6e82a65 Iustin Pop
      if self.opts.iallocator:
606 b6e82a65 Iustin Pop
        tnode = None
607 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
608 836d59d7 Iustin Pop
      else:
609 836d59d7 Iustin Pop
        msg = tnode
610 175f44c2 Iustin Pop
      op = opcodes.OpReplaceDisks(instance_name=instance,
611 175f44c2 Iustin Pop
                                  mode=mode,
612 175f44c2 Iustin Pop
                                  remote_node=tnode,
613 b6e82a65 Iustin Pop
                                  iallocator=self.opts.iallocator,
614 7ea7bcf6 Iustin Pop
                                  disks=[],
615 7ea7bcf6 Iustin Pop
                                  early_release=self.opts.early_release)
616 1b334175 Iustin Pop
      Log("run %s %s", mode, msg, indent=2)
617 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
618 175f44c2 Iustin Pop
619 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
620 c70481ab Iustin Pop
  @_DoBatch(False)
621 c723c163 Iustin Pop
  def BurnFailover(self):
622 175f44c2 Iustin Pop
    """Failover the instances."""
623 836d59d7 Iustin Pop
    Log("Failing over instances")
624 175f44c2 Iustin Pop
    for instance in self.instances:
625 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
626 175f44c2 Iustin Pop
      op = opcodes.OpFailoverInstance(instance_name=instance,
627 175f44c2 Iustin Pop
                                      ignore_consistency=False)
628 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
629 175f44c2 Iustin Pop
630 5b9107ff Iustin Pop
  @_DoCheckInstances
631 5b9107ff Iustin Pop
  @_DoBatch(False)
632 5b9107ff Iustin Pop
  def BurnMove(self):
633 5b9107ff Iustin Pop
    """Move the instances."""
634 5b9107ff Iustin Pop
    Log("Moving instances")
635 5b9107ff Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 1, None),
636 5b9107ff Iustin Pop
                 self.instances)
637 5b9107ff Iustin Pop
    for tnode, instance in mytor:
638 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
639 5b9107ff Iustin Pop
      op = opcodes.OpMoveInstance(instance_name=instance,
640 5b9107ff Iustin Pop
                                  target_node=tnode)
641 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
642 175f44c2 Iustin Pop
643 c70481ab Iustin Pop
  @_DoBatch(False)
644 c723c163 Iustin Pop
  def BurnMigrate(self):
645 99bdd139 Iustin Pop
    """Migrate the instances."""
646 801cda94 Iustin Pop
    Log("Migrating instances")
647 99bdd139 Iustin Pop
    for instance in self.instances:
648 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
649 c723c163 Iustin Pop
      op1 = opcodes.OpMigrateInstance(instance_name=instance, live=True,
650 c723c163 Iustin Pop
                                      cleanup=False)
651 99bdd139 Iustin Pop
652 c723c163 Iustin Pop
      op2 = opcodes.OpMigrateInstance(instance_name=instance, live=True,
653 c723c163 Iustin Pop
                                      cleanup=True)
654 c723c163 Iustin Pop
      Log("migration and migration cleanup", indent=2)
655 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2])
656 99bdd139 Iustin Pop
657 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
658 c70481ab Iustin Pop
  @_DoBatch(False)
659 c723c163 Iustin Pop
  def BurnImportExport(self):
660 bd5e77f9 Guido Trotter
    """Export the instance, delete it, and import it back.
661 bd5e77f9 Guido Trotter
662 bd5e77f9 Guido Trotter
    """
663 836d59d7 Iustin Pop
    Log("Exporting and re-importing instances")
664 bd5e77f9 Guido Trotter
    mytor = izip(cycle(self.nodes),
665 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 1, None),
666 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 2, None),
667 bd5e77f9 Guido Trotter
                 self.instances)
668 bd5e77f9 Guido Trotter
669 bd5e77f9 Guido Trotter
    for pnode, snode, enode, instance in mytor:
670 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
671 c723c163 Iustin Pop
      # read the full name of the instance
672 c723c163 Iustin Pop
      nam_op = opcodes.OpQueryInstances(output_fields=["name"],
673 ec79568d Iustin Pop
                                        names=[instance], use_locking=True)
674 73ff3118 Iustin Pop
      full_name = self.ExecOp(False, nam_op)[0][0]
675 c723c163 Iustin Pop
676 f9af35c8 Guido Trotter
      if self.opts.iallocator:
677 f9af35c8 Guido Trotter
        pnode = snode = None
678 836d59d7 Iustin Pop
        import_log_msg = ("import from %s"
679 836d59d7 Iustin Pop
                          " with iallocator %s" %
680 836d59d7 Iustin Pop
                          (enode, self.opts.iallocator))
681 f9af35c8 Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
682 f9af35c8 Guido Trotter
        snode = None
683 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s" %
684 836d59d7 Iustin Pop
                          (enode, pnode))
685 f9af35c8 Guido Trotter
      else:
686 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s, %s" %
687 836d59d7 Iustin Pop
                          (enode, pnode, snode))
688 f9af35c8 Guido Trotter
689 bd5e77f9 Guido Trotter
      exp_op = opcodes.OpExportInstance(instance_name=instance,
690 bd5e77f9 Guido Trotter
                                           target_node=enode,
691 bd5e77f9 Guido Trotter
                                           shutdown=True)
692 5c54b832 Iustin Pop
      rem_op = opcodes.OpRemoveInstance(instance_name=instance,
693 5c54b832 Iustin Pop
                                        ignore_failures=True)
694 c4feafe8 Iustin Pop
      imp_dir = utils.PathJoin(constants.EXPORT_DIR, full_name)
695 bd5e77f9 Guido Trotter
      imp_op = opcodes.OpCreateInstance(instance_name=instance,
696 0ca35d45 Guido Trotter
                                        disks = [ {"size": size}
697 0ca35d45 Guido Trotter
                                                  for size in self.disk_size],
698 bd5e77f9 Guido Trotter
                                        disk_template=self.opts.disk_template,
699 b518a14a Iustin Pop
                                        nics=self.opts.nics,
700 bd5e77f9 Guido Trotter
                                        mode=constants.INSTANCE_IMPORT,
701 bd5e77f9 Guido Trotter
                                        src_node=enode,
702 bd5e77f9 Guido Trotter
                                        src_path=imp_dir,
703 bd5e77f9 Guido Trotter
                                        pnode=pnode,
704 bd5e77f9 Guido Trotter
                                        snode=snode,
705 bd5e77f9 Guido Trotter
                                        start=True,
706 544ca43b Iustin Pop
                                        ip_check=self.opts.ip_check,
707 544ca43b Iustin Pop
                                        name_check=self.opts.name_check,
708 bd5e77f9 Guido Trotter
                                        wait_for_sync=True,
709 96bb2f71 Manuel Franceschini
                                        file_storage_dir=None,
710 0ca35d45 Guido Trotter
                                        file_driver="loop",
711 6e2dc934 Alexander Schreiber
                                        iallocator=self.opts.iallocator,
712 338e51e8 Iustin Pop
                                        beparams=self.bep,
713 338e51e8 Iustin Pop
                                        hvparams=self.hvp,
714 338e51e8 Iustin Pop
                                        )
715 6e2dc934 Alexander Schreiber
716 4a7ff493 Guido Trotter
      erem_op = opcodes.OpRemoveExport(instance_name=instance)
717 bd5e77f9 Guido Trotter
718 1b334175 Iustin Pop
      Log("export to node %s", enode, indent=2)
719 836d59d7 Iustin Pop
      Log("remove instance", indent=2)
720 836d59d7 Iustin Pop
      Log(import_log_msg, indent=2)
721 836d59d7 Iustin Pop
      Log("remove export", indent=2)
722 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [exp_op, rem_op, imp_op, erem_op])
723 bd5e77f9 Guido Trotter
724 7e950d31 Iustin Pop
  @staticmethod
725 7e950d31 Iustin Pop
  def StopInstanceOp(instance):
726 054a8696 Manuel Franceschini
    """Stop given instance."""
727 c723c163 Iustin Pop
    return opcodes.OpShutdownInstance(instance_name=instance)
728 054a8696 Manuel Franceschini
729 7e950d31 Iustin Pop
  @staticmethod
730 7e950d31 Iustin Pop
  def StartInstanceOp(instance):
731 054a8696 Manuel Franceschini
    """Start given instance."""
732 c723c163 Iustin Pop
    return opcodes.OpStartupInstance(instance_name=instance, force=False)
733 054a8696 Manuel Franceschini
734 7e950d31 Iustin Pop
  @staticmethod
735 7e950d31 Iustin Pop
  def RenameInstanceOp(instance, instance_new):
736 054a8696 Manuel Franceschini
    """Rename instance."""
737 c723c163 Iustin Pop
    return opcodes.OpRenameInstance(instance_name=instance,
738 c723c163 Iustin Pop
                                    new_name=instance_new)
739 054a8696 Manuel Franceschini
740 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
741 c70481ab Iustin Pop
  @_DoBatch(True)
742 c723c163 Iustin Pop
  def BurnStopStart(self):
743 175f44c2 Iustin Pop
    """Stop/start the instances."""
744 836d59d7 Iustin Pop
    Log("Stopping and starting instances")
745 175f44c2 Iustin Pop
    for instance in self.instances:
746 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
747 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
748 c723c163 Iustin Pop
      op2 = self.StartInstanceOp(instance)
749 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2])
750 c723c163 Iustin Pop
751 c70481ab Iustin Pop
  @_DoBatch(False)
752 c723c163 Iustin Pop
  def BurnRemove(self):
753 175f44c2 Iustin Pop
    """Remove the instances."""
754 836d59d7 Iustin Pop
    Log("Removing instances")
755 175f44c2 Iustin Pop
    for instance in self.to_rem:
756 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
757 5c54b832 Iustin Pop
      op = opcodes.OpRemoveInstance(instance_name=instance,
758 5c54b832 Iustin Pop
                                    ignore_failures=True)
759 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
760 c723c163 Iustin Pop
761 c723c163 Iustin Pop
  def BurnRename(self):
762 c723c163 Iustin Pop
    """Rename the instances.
763 175f44c2 Iustin Pop
764 c723c163 Iustin Pop
    Note that this function will not execute in parallel, since we
765 c723c163 Iustin Pop
    only have one target for rename.
766 c723c163 Iustin Pop
767 c723c163 Iustin Pop
    """
768 836d59d7 Iustin Pop
    Log("Renaming instances")
769 054a8696 Manuel Franceschini
    rename = self.opts.rename
770 054a8696 Manuel Franceschini
    for instance in self.instances:
771 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
772 2e39ab98 Iustin Pop
      op_stop1 = self.StopInstanceOp(instance)
773 2e39ab98 Iustin Pop
      op_stop2 = self.StopInstanceOp(rename)
774 c723c163 Iustin Pop
      op_rename1 = self.RenameInstanceOp(instance, rename)
775 c723c163 Iustin Pop
      op_rename2 = self.RenameInstanceOp(rename, instance)
776 c723c163 Iustin Pop
      op_start1 = self.StartInstanceOp(rename)
777 c723c163 Iustin Pop
      op_start2 = self.StartInstanceOp(instance)
778 73ff3118 Iustin Pop
      self.ExecOp(False, op_stop1, op_rename1, op_start1)
779 5178f1bc Iustin Pop
      self._CheckInstanceAlive(rename)
780 73ff3118 Iustin Pop
      self.ExecOp(False, op_stop2, op_rename2, op_start2)
781 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
782 5178f1bc Iustin Pop
783 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
784 c70481ab Iustin Pop
  @_DoBatch(True)
785 c723c163 Iustin Pop
  def BurnReinstall(self):
786 00f91f29 Iustin Pop
    """Reinstall the instances."""
787 836d59d7 Iustin Pop
    Log("Reinstalling instances")
788 00f91f29 Iustin Pop
    for instance in self.instances:
789 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
790 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
791 c723c163 Iustin Pop
      op2 = opcodes.OpReinstallInstance(instance_name=instance)
792 836d59d7 Iustin Pop
      Log("reinstall without passing the OS", indent=2)
793 c723c163 Iustin Pop
      op3 = opcodes.OpReinstallInstance(instance_name=instance,
794 c723c163 Iustin Pop
                                        os_type=self.opts.os)
795 836d59d7 Iustin Pop
      Log("reinstall specifying the OS", indent=2)
796 c723c163 Iustin Pop
      op4 = self.StartInstanceOp(instance)
797 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2, op3, op4])
798 c723c163 Iustin Pop
799 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
800 c70481ab Iustin Pop
  @_DoBatch(True)
801 c723c163 Iustin Pop
  def BurnReboot(self):
802 836d59d7 Iustin Pop
    """Reboot the instances."""
803 836d59d7 Iustin Pop
    Log("Rebooting instances")
804 00f91f29 Iustin Pop
    for instance in self.instances:
805 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
806 c723c163 Iustin Pop
      ops = []
807 00f91f29 Iustin Pop
      for reboot_type in constants.REBOOT_TYPES:
808 00f91f29 Iustin Pop
        op = opcodes.OpRebootInstance(instance_name=instance,
809 00f91f29 Iustin Pop
                                      reboot_type=reboot_type,
810 00f91f29 Iustin Pop
                                      ignore_secondaries=False)
811 1b334175 Iustin Pop
        Log("reboot with type '%s'", reboot_type, indent=2)
812 c723c163 Iustin Pop
        ops.append(op)
813 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, ops)
814 c723c163 Iustin Pop
815 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
816 c70481ab Iustin Pop
  @_DoBatch(True)
817 c723c163 Iustin Pop
  def BurnActivateDisks(self):
818 90e722d1 Iustin Pop
    """Activate and deactivate disks of the instances."""
819 836d59d7 Iustin Pop
    Log("Activating/deactivating disks")
820 90e722d1 Iustin Pop
    for instance in self.instances:
821 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
822 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
823 90e722d1 Iustin Pop
      op_act = opcodes.OpActivateInstanceDisks(instance_name=instance)
824 90e722d1 Iustin Pop
      op_deact = opcodes.OpDeactivateInstanceDisks(instance_name=instance)
825 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
826 836d59d7 Iustin Pop
      Log("activate disks when online", indent=2)
827 836d59d7 Iustin Pop
      Log("activate disks when offline", indent=2)
828 836d59d7 Iustin Pop
      Log("deactivate disks (when offline)", indent=2)
829 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_act, op_stop, op_act, op_deact, op_start])
830 90e722d1 Iustin Pop
831 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
832 c70481ab Iustin Pop
  @_DoBatch(False)
833 c723c163 Iustin Pop
  def BurnAddRemoveDisks(self):
834 5c22d16e Iustin Pop
    """Add and remove an extra disk for the instances."""
835 836d59d7 Iustin Pop
    Log("Adding and removing disks")
836 5c22d16e Iustin Pop
    for instance in self.instances:
837 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
838 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
839 5c22d16e Iustin Pop
        instance_name=instance,
840 5c22d16e Iustin Pop
        disks=[(constants.DDM_ADD, {"size": self.disk_size[0]})])
841 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
842 5c22d16e Iustin Pop
        instance_name=instance, disks=[(constants.DDM_REMOVE, {})])
843 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
844 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
845 836d59d7 Iustin Pop
      Log("adding a disk", indent=2)
846 836d59d7 Iustin Pop
      Log("removing last disk", indent=2)
847 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_add, op_stop, op_rem, op_start])
848 5c22d16e Iustin Pop
849 c70481ab Iustin Pop
  @_DoBatch(False)
850 c723c163 Iustin Pop
  def BurnAddRemoveNICs(self):
851 5c22d16e Iustin Pop
    """Add and remove an extra NIC for the instances."""
852 836d59d7 Iustin Pop
    Log("Adding and removing NICs")
853 5c22d16e Iustin Pop
    for instance in self.instances:
854 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
855 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
856 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_ADD, {})])
857 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
858 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_REMOVE, {})])
859 836d59d7 Iustin Pop
      Log("adding a NIC", indent=2)
860 836d59d7 Iustin Pop
      Log("removing last NIC", indent=2)
861 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_add, op_rem])
862 5c22d16e Iustin Pop
863 a619a1dd Guido Trotter
  def ConfdCallback(self, reply):
864 a619a1dd Guido Trotter
    """Callback for confd queries"""
865 a619a1dd Guido Trotter
    if reply.type == confd_client.UPCALL_REPLY:
866 a619a1dd Guido Trotter
      if reply.server_reply.status != constants.CONFD_REPL_STATUS_OK:
867 a619a1dd Guido Trotter
        Err("Query %s gave non-ok status %s: %s" % (reply.orig_request,
868 a619a1dd Guido Trotter
                                                    reply.server_reply.status,
869 a619a1dd Guido Trotter
                                                    reply.server_reply))
870 a619a1dd Guido Trotter
      if reply.orig_request.type == constants.CONFD_REQ_PING:
871 a619a1dd Guido Trotter
        Log("Ping: OK", indent=1)
872 a619a1dd Guido Trotter
      elif reply.orig_request.type == constants.CONFD_REQ_CLUSTER_MASTER:
873 a619a1dd Guido Trotter
        if reply.server_reply.answer == self.cluster_info["master"]:
874 a619a1dd Guido Trotter
          Log("Master: OK", indent=1)
875 a619a1dd Guido Trotter
        else:
876 a619a1dd Guido Trotter
          Err("Master: wrong: %s" % reply.server_reply.answer)
877 a619a1dd Guido Trotter
      elif reply.orig_request.type == constants.CONFD_REQ_NODE_ROLE_BYNAME:
878 a619a1dd Guido Trotter
        if reply.server_reply.answer == constants.CONFD_NODE_ROLE_MASTER:
879 a619a1dd Guido Trotter
          Log("Node role for master: OK", indent=1)
880 a619a1dd Guido Trotter
        else:
881 a619a1dd Guido Trotter
          Err("Node role for master: wrong: %s" % reply.server_reply.answer)
882 a619a1dd Guido Trotter
883 a619a1dd Guido Trotter
  def DoConfdRequestReply(self, req):
884 a619a1dd Guido Trotter
    self.confd_counting_callback.RegisterQuery(req.rsalt)
885 a619a1dd Guido Trotter
    self.confd_client.SendRequest(req, async=False)
886 a619a1dd Guido Trotter
    while not self.confd_counting_callback.AllAnswered():
887 a619a1dd Guido Trotter
      if not self.confd_client.ReceiveReply():
888 a619a1dd Guido Trotter
        Err("Did not receive all expected confd replies")
889 a619a1dd Guido Trotter
        break
890 a619a1dd Guido Trotter
891 a619a1dd Guido Trotter
  def BurnConfd(self):
892 a619a1dd Guido Trotter
    """Run confd queries for our instances.
893 a619a1dd Guido Trotter
894 a619a1dd Guido Trotter
    The following confd queries are tested:
895 a619a1dd Guido Trotter
    - CONFD_REQ_PING: simple ping
896 a619a1dd Guido Trotter
    - CONFD_REQ_CLUSTER_MASTER: cluster master
897 a619a1dd Guido Trotter
    - CONFD_REQ_NODE_ROLE_BYNAME: node role, for the master
898 a619a1dd Guido Trotter
899 a619a1dd Guido Trotter
    """
900 a619a1dd Guido Trotter
    Log("Checking confd results")
901 a619a1dd Guido Trotter
902 a619a1dd Guido Trotter
    filter_callback = confd_client.ConfdFilterCallback(self.ConfdCallback)
903 a619a1dd Guido Trotter
    counting_callback = confd_client.ConfdCountingCallback(filter_callback)
904 a619a1dd Guido Trotter
    self.confd_counting_callback = counting_callback
905 a619a1dd Guido Trotter
906 5b349fd1 Iustin Pop
    self.confd_client = confd_client.GetConfdClient(counting_callback)
907 a619a1dd Guido Trotter
908 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
909 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
910 a619a1dd Guido Trotter
911 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(
912 a619a1dd Guido Trotter
      type=constants.CONFD_REQ_CLUSTER_MASTER)
913 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
914 a619a1dd Guido Trotter
915 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(
916 a619a1dd Guido Trotter
        type=constants.CONFD_REQ_NODE_ROLE_BYNAME,
917 a619a1dd Guido Trotter
        query=self.cluster_info["master"])
918 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
919 a619a1dd Guido Trotter
920 5178f1bc Iustin Pop
  def _CheckInstanceAlive(self, instance):
921 5178f1bc Iustin Pop
    """Check if an instance is alive by doing http checks.
922 5178f1bc Iustin Pop
923 5178f1bc Iustin Pop
    This will try to retrieve the url on the instance /hostname.txt
924 5178f1bc Iustin Pop
    and check that it contains the hostname of the instance. In case
925 5178f1bc Iustin Pop
    we get ECONNREFUSED, we retry up to the net timeout seconds, for
926 5178f1bc Iustin Pop
    any other error we abort.
927 5178f1bc Iustin Pop
928 5178f1bc Iustin Pop
    """
929 5178f1bc Iustin Pop
    if not self.opts.http_check:
930 5178f1bc Iustin Pop
      return
931 5dc626fd Iustin Pop
    end_time = time.time() + self.opts.net_timeout
932 5dc626fd Iustin Pop
    url = None
933 5dc626fd Iustin Pop
    while time.time() < end_time and url is None:
934 5dc626fd Iustin Pop
      try:
935 5dc626fd Iustin Pop
        url = self.url_opener.open("http://%s/hostname.txt" % instance)
936 c723c163 Iustin Pop
      except IOError:
937 5dc626fd Iustin Pop
        # here we can have connection refused, no route to host, etc.
938 5dc626fd Iustin Pop
        time.sleep(1)
939 5dc626fd Iustin Pop
    if url is None:
940 5dc626fd Iustin Pop
      raise InstanceDown(instance, "Cannot contact instance")
941 5178f1bc Iustin Pop
    hostname = url.read().strip()
942 5dc626fd Iustin Pop
    url.close()
943 5178f1bc Iustin Pop
    if hostname != instance:
944 5178f1bc Iustin Pop
      raise InstanceDown(instance, ("Hostname mismatch, expected %s, got %s" %
945 5178f1bc Iustin Pop
                                    (instance, hostname)))
946 5178f1bc Iustin Pop
947 175f44c2 Iustin Pop
  def BurninCluster(self):
948 175f44c2 Iustin Pop
    """Test a cluster intensively.
949 175f44c2 Iustin Pop
950 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
951 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
952 175f44c2 Iustin Pop
953 175f44c2 Iustin Pop
    """
954 175f44c2 Iustin Pop
955 175f44c2 Iustin Pop
    opts = self.opts
956 175f44c2 Iustin Pop
957 836d59d7 Iustin Pop
    Log("Testing global parameters")
958 175f44c2 Iustin Pop
959 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
960 2f505cb5 Manuel Franceschini
        opts.disk_template not in (constants.DT_DISKLESS, constants.DT_PLAIN,
961 2f505cb5 Manuel Franceschini
                                   constants.DT_FILE)):
962 836d59d7 Iustin Pop
      Err("When one node is available/selected the disk template must"
963 2f505cb5 Manuel Franceschini
          " be 'diskless', 'file' or 'plain'")
964 175f44c2 Iustin Pop
965 21546b1c Iustin Pop
    has_err = True
966 175f44c2 Iustin Pop
    try:
967 c723c163 Iustin Pop
      self.BurnCreateInstances()
968 175f44c2 Iustin Pop
      if opts.do_replace1 and opts.disk_template in constants.DTS_NET_MIRROR:
969 c723c163 Iustin Pop
        self.BurnReplaceDisks1D8()
970 175f44c2 Iustin Pop
      if (opts.do_replace2 and len(self.nodes) > 2 and
971 175f44c2 Iustin Pop
          opts.disk_template in constants.DTS_NET_MIRROR) :
972 c723c163 Iustin Pop
        self.BurnReplaceDisks2()
973 175f44c2 Iustin Pop
974 728489a3 Guido Trotter
      if (opts.disk_template in constants.DTS_GROWABLE and
975 aa089b65 Iustin Pop
          utils.any(self.disk_growth, lambda n: n > 0)):
976 c723c163 Iustin Pop
        self.BurnGrowDisks()
977 659712c8 Iustin Pop
978 175f44c2 Iustin Pop
      if opts.do_failover and opts.disk_template in constants.DTS_NET_MIRROR:
979 c723c163 Iustin Pop
        self.BurnFailover()
980 175f44c2 Iustin Pop
981 99bdd139 Iustin Pop
      if opts.do_migrate and opts.disk_template == constants.DT_DRBD8:
982 c723c163 Iustin Pop
        self.BurnMigrate()
983 99bdd139 Iustin Pop
984 9e32b93b Guido Trotter
      if (opts.do_move and len(self.nodes) > 1 and
985 9e32b93b Guido Trotter
          opts.disk_template in [constants.DT_PLAIN, constants.DT_FILE]):
986 5b9107ff Iustin Pop
        self.BurnMove()
987 5b9107ff Iustin Pop
988 a5e7be6b Iustin Pop
      if (opts.do_importexport and
989 a5e7be6b Iustin Pop
          opts.disk_template not in (constants.DT_DISKLESS,
990 a5e7be6b Iustin Pop
                                     constants.DT_FILE)):
991 c723c163 Iustin Pop
        self.BurnImportExport()
992 bd5e77f9 Guido Trotter
993 00f91f29 Iustin Pop
      if opts.do_reinstall:
994 c723c163 Iustin Pop
        self.BurnReinstall()
995 00f91f29 Iustin Pop
996 00f91f29 Iustin Pop
      if opts.do_reboot:
997 c723c163 Iustin Pop
        self.BurnReboot()
998 00f91f29 Iustin Pop
999 5c22d16e Iustin Pop
      if opts.do_addremove_disks:
1000 c723c163 Iustin Pop
        self.BurnAddRemoveDisks()
1001 5c22d16e Iustin Pop
1002 be0636e3 Guido Trotter
      default_nic_mode = self.cluster_default_nicparams[constants.NIC_MODE]
1003 be0636e3 Guido Trotter
      # Don't add/remove nics in routed mode, as we would need an ip to add
1004 be0636e3 Guido Trotter
      # them with
1005 5c22d16e Iustin Pop
      if opts.do_addremove_nics:
1006 be0636e3 Guido Trotter
        if default_nic_mode == constants.NIC_MODE_BRIDGED:
1007 be0636e3 Guido Trotter
          self.BurnAddRemoveNICs()
1008 be0636e3 Guido Trotter
        else:
1009 be0636e3 Guido Trotter
          Log("Skipping nic add/remove as the cluster is not in bridged mode")
1010 5c22d16e Iustin Pop
1011 90e722d1 Iustin Pop
      if opts.do_activate_disks:
1012 c723c163 Iustin Pop
        self.BurnActivateDisks()
1013 90e722d1 Iustin Pop
1014 054a8696 Manuel Franceschini
      if opts.rename:
1015 c723c163 Iustin Pop
        self.BurnRename()
1016 054a8696 Manuel Franceschini
1017 a619a1dd Guido Trotter
      if opts.do_confd_tests:
1018 a619a1dd Guido Trotter
        self.BurnConfd()
1019 a619a1dd Guido Trotter
1020 eb61f8d3 Iustin Pop
      if opts.do_startstop:
1021 c723c163 Iustin Pop
        self.BurnStopStart()
1022 eb61f8d3 Iustin Pop
1023 21546b1c Iustin Pop
      has_err = False
1024 175f44c2 Iustin Pop
    finally:
1025 21546b1c Iustin Pop
      if has_err:
1026 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
1027 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
1028 21546b1c Iustin Pop
        Log("\n\n")
1029 320eda24 Iustin Pop
      if not self.opts.keep_instances:
1030 8629a543 Iustin Pop
        try:
1031 8629a543 Iustin Pop
          self.BurnRemove()
1032 7260cfbe Iustin Pop
        except Exception, err:  # pylint: disable-msg=W0703
1033 8629a543 Iustin Pop
          if has_err: # already detected errors, so errors in removal
1034 8629a543 Iustin Pop
                      # are quite expected
1035 1b334175 Iustin Pop
            Log("Note: error detected during instance remove: %s", err)
1036 8629a543 Iustin Pop
          else: # non-expected error
1037 8629a543 Iustin Pop
            raise
1038 175f44c2 Iustin Pop
1039 175f44c2 Iustin Pop
    return 0
1040 a8083063 Iustin Pop
1041 01b69ec5 Michael Hanselmann
1042 a8083063 Iustin Pop
def main():
1043 3ecf6786 Iustin Pop
  """Main function"""
1044 3ecf6786 Iustin Pop
1045 175f44c2 Iustin Pop
  burner = Burner()
1046 a4af651e Iustin Pop
  return burner.BurninCluster()
1047 a8083063 Iustin Pop
1048 01b69ec5 Michael Hanselmann
1049 a8083063 Iustin Pop
if __name__ == "__main__":
1050 3ecf6786 Iustin Pop
  main()