Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 728489a3

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