Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ a536aaac

History | View | Annotate | Download (38.4 kB)

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