Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 24f6a6e6

History | View | Annotate | Download (38.2 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 f907fcf2 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 82d9caef Iustin Pop
    utils.SetupLogging(constants.LOG_BURNIN, debug=False, stderr_logging=True)
262 5dc626fd Iustin Pop
    self.url_opener = SimpleOpener()
263 21546b1c Iustin Pop
    self._feed_buf = StringIO()
264 175f44c2 Iustin Pop
    self.nodes = []
265 175f44c2 Iustin Pop
    self.instances = []
266 175f44c2 Iustin Pop
    self.to_rem = []
267 c723c163 Iustin Pop
    self.queued_ops = []
268 175f44c2 Iustin Pop
    self.opts = None
269 73ff3118 Iustin Pop
    self.queue_retry = False
270 73ff3118 Iustin Pop
    self.disk_count = self.disk_growth = self.disk_size = None
271 73ff3118 Iustin Pop
    self.hvp = self.bep = None
272 175f44c2 Iustin Pop
    self.ParseOptions()
273 320eda24 Iustin Pop
    self.cl = cli.GetClient()
274 175f44c2 Iustin Pop
    self.GetState()
275 175f44c2 Iustin Pop
276 21546b1c Iustin Pop
  def ClearFeedbackBuf(self):
277 21546b1c Iustin Pop
    """Clear the feedback buffer."""
278 21546b1c Iustin Pop
    self._feed_buf.truncate(0)
279 21546b1c Iustin Pop
280 21546b1c Iustin Pop
  def GetFeedbackBuf(self):
281 21546b1c Iustin Pop
    """Return the contents of the buffer."""
282 21546b1c Iustin Pop
    return self._feed_buf.getvalue()
283 21546b1c Iustin Pop
284 21546b1c Iustin Pop
  def Feedback(self, msg):
285 21546b1c Iustin Pop
    """Acumulate feedback in our buffer."""
286 88d31e5c Iustin Pop
    formatted_msg = "%s %s" % (time.ctime(utils.MergeTime(msg[0])), msg[2])
287 88d31e5c Iustin Pop
    self._feed_buf.write(formatted_msg + "\n")
288 d7b47a77 Iustin Pop
    if self.opts.verbose:
289 88d31e5c Iustin Pop
      Log(formatted_msg, indent=3)
290 21546b1c Iustin Pop
291 73ff3118 Iustin Pop
  def MaybeRetry(self, retry_count, msg, fn, *args):
292 73ff3118 Iustin Pop
    """Possibly retry a given function execution.
293 73ff3118 Iustin Pop
294 73ff3118 Iustin Pop
    @type retry_count: int
295 73ff3118 Iustin Pop
    @param retry_count: retry counter:
296 73ff3118 Iustin Pop
        - 0: non-retryable action
297 73ff3118 Iustin Pop
        - 1: last retry for a retryable action
298 73ff3118 Iustin Pop
        - MAX_RETRIES: original try for a retryable action
299 73ff3118 Iustin Pop
    @type msg: str
300 73ff3118 Iustin Pop
    @param msg: the kind of the operation
301 73ff3118 Iustin Pop
    @type fn: callable
302 73ff3118 Iustin Pop
    @param fn: the function to be called
303 73ff3118 Iustin Pop
304 73ff3118 Iustin Pop
    """
305 73ff3118 Iustin Pop
    try:
306 73ff3118 Iustin Pop
      val = fn(*args)
307 73ff3118 Iustin Pop
      if retry_count > 0 and retry_count < MAX_RETRIES:
308 1b334175 Iustin Pop
        Log("Idempotent %s succeeded after %d retries",
309 1b334175 Iustin Pop
            msg, MAX_RETRIES - retry_count)
310 73ff3118 Iustin Pop
      return val
311 7260cfbe Iustin Pop
    except Exception, err: # pylint: disable-msg=W0703
312 73ff3118 Iustin Pop
      if retry_count == 0:
313 1b334175 Iustin Pop
        Log("Non-idempotent %s failed, aborting", msg)
314 73ff3118 Iustin Pop
        raise
315 73ff3118 Iustin Pop
      elif retry_count == 1:
316 1b334175 Iustin Pop
        Log("Idempotent %s repeated failure, aborting", msg)
317 73ff3118 Iustin Pop
        raise
318 73ff3118 Iustin Pop
      else:
319 1b334175 Iustin Pop
        Log("Idempotent %s failed, retry #%d/%d: %s",
320 1b334175 Iustin Pop
            msg, MAX_RETRIES - retry_count + 1, MAX_RETRIES, err)
321 73ff3118 Iustin Pop
        self.MaybeRetry(retry_count - 1, msg, fn, *args)
322 73ff3118 Iustin Pop
323 265e6244 Iustin Pop
  def _SetDebug(self, ops):
324 265e6244 Iustin Pop
    """Set the debug value on the given opcodes"""
325 265e6244 Iustin Pop
    for op in ops:
326 265e6244 Iustin Pop
      op.debug_level = self.opts.debug
327 265e6244 Iustin Pop
328 73ff3118 Iustin Pop
  def _ExecOp(self, *ops):
329 c723c163 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
330 c723c163 Iustin Pop
331 454723b5 Iustin Pop
    @return: if only opcode has been passed, we return its result;
332 c723c163 Iustin Pop
        otherwise we return the list of results
333 c723c163 Iustin Pop
334 c723c163 Iustin Pop
    """
335 c723c163 Iustin Pop
    job_id = cli.SendJob(ops, cl=self.cl)
336 c723c163 Iustin Pop
    results = cli.PollJob(job_id, cl=self.cl, feedback_fn=self.Feedback)
337 c723c163 Iustin Pop
    if len(ops) == 1:
338 c723c163 Iustin Pop
      return results[0]
339 c723c163 Iustin Pop
    else:
340 c723c163 Iustin Pop
      return results
341 c723c163 Iustin Pop
342 73ff3118 Iustin Pop
  def ExecOp(self, retry, *ops):
343 73ff3118 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
344 73ff3118 Iustin Pop
345 454723b5 Iustin Pop
    @return: if only opcode has been passed, we return its result;
346 73ff3118 Iustin Pop
        otherwise we return the list of results
347 73ff3118 Iustin Pop
348 73ff3118 Iustin Pop
    """
349 73ff3118 Iustin Pop
    if retry:
350 73ff3118 Iustin Pop
      rval = MAX_RETRIES
351 73ff3118 Iustin Pop
    else:
352 73ff3118 Iustin Pop
      rval = 0
353 265e6244 Iustin Pop
    self._SetDebug(ops)
354 73ff3118 Iustin Pop
    return self.MaybeRetry(rval, "opcode", self._ExecOp, *ops)
355 73ff3118 Iustin Pop
356 2c035435 Guido Trotter
  def ExecOrQueue(self, name, ops, post_process=None):
357 21546b1c Iustin Pop
    """Execute an opcode and manage the exec buffer."""
358 c723c163 Iustin Pop
    if self.opts.parallel:
359 265e6244 Iustin Pop
      self._SetDebug(ops)
360 2c035435 Guido Trotter
      self.queued_ops.append((ops, name, post_process))
361 c723c163 Iustin Pop
    else:
362 2c035435 Guido Trotter
      val = self.ExecOp(self.queue_retry, *ops) # pylint: disable-msg=W0142
363 2c035435 Guido Trotter
      if post_process is not None:
364 2c035435 Guido Trotter
        post_process()
365 2c035435 Guido Trotter
      return val
366 73ff3118 Iustin Pop
367 73ff3118 Iustin Pop
  def StartBatch(self, retry):
368 73ff3118 Iustin Pop
    """Start a new batch of jobs.
369 73ff3118 Iustin Pop
370 73ff3118 Iustin Pop
    @param retry: whether this is a retryable batch
371 73ff3118 Iustin Pop
372 73ff3118 Iustin Pop
    """
373 73ff3118 Iustin Pop
    self.queued_ops = []
374 73ff3118 Iustin Pop
    self.queue_retry = retry
375 c723c163 Iustin Pop
376 c723c163 Iustin Pop
  def CommitQueue(self):
377 c723c163 Iustin Pop
    """Execute all submitted opcodes in case of parallel burnin"""
378 78bb78b1 Iustin Pop
    if not self.opts.parallel or not self.queued_ops:
379 c723c163 Iustin Pop
      return
380 c723c163 Iustin Pop
381 73ff3118 Iustin Pop
    if self.queue_retry:
382 73ff3118 Iustin Pop
      rval = MAX_RETRIES
383 73ff3118 Iustin Pop
    else:
384 73ff3118 Iustin Pop
      rval = 0
385 73ff3118 Iustin Pop
386 c723c163 Iustin Pop
    try:
387 73ff3118 Iustin Pop
      results = self.MaybeRetry(rval, "jobset", self.ExecJobSet,
388 73ff3118 Iustin Pop
                                self.queued_ops)
389 c723c163 Iustin Pop
    finally:
390 c723c163 Iustin Pop
      self.queued_ops = []
391 c723c163 Iustin Pop
    return results
392 ec5c88dc Iustin Pop
393 ec5c88dc Iustin Pop
  def ExecJobSet(self, jobs):
394 ec5c88dc Iustin Pop
    """Execute a set of jobs and return once all are done.
395 ec5c88dc Iustin Pop
396 ec5c88dc Iustin Pop
    The method will return the list of results, if all jobs are
397 c723c163 Iustin Pop
    successful. Otherwise, OpExecError will be raised from within
398 ec5c88dc Iustin Pop
    cli.py.
399 ec5c88dc Iustin Pop
400 ec5c88dc Iustin Pop
    """
401 ec5c88dc Iustin Pop
    self.ClearFeedbackBuf()
402 14947dbc Iustin Pop
    jex = cli.JobExecutor(cl=self.cl, feedback_fn=self.Feedback)
403 2c035435 Guido Trotter
    for ops, name, _ in jobs:
404 14947dbc Iustin Pop
      jex.QueueJob(name, *ops) # pylint: disable-msg=W0142
405 14947dbc Iustin Pop
    try:
406 14947dbc Iustin Pop
      results = jex.GetResults()
407 14947dbc Iustin Pop
    except Exception, err: # pylint: disable-msg=W0703
408 14947dbc Iustin Pop
      Log("Jobs failed: %s", err)
409 73ff3118 Iustin Pop
      raise BurninFailure()
410 14947dbc Iustin Pop
411 2c035435 Guido Trotter
    fail = False
412 2c035435 Guido Trotter
    val = []
413 2c035435 Guido Trotter
    for (_, name, post_process), (success, result) in zip(jobs, results):
414 2c035435 Guido Trotter
      if success:
415 2c035435 Guido Trotter
        if post_process:
416 2c035435 Guido Trotter
          try:
417 2c035435 Guido Trotter
            post_process()
418 2c035435 Guido Trotter
          except Exception, err: # pylint: disable-msg=W0703
419 2c035435 Guido Trotter
            Log("Post process call for job %s failed: %s", name, err)
420 2c035435 Guido Trotter
            fail = True
421 2c035435 Guido Trotter
        val.append(result)
422 2c035435 Guido Trotter
      else:
423 2c035435 Guido Trotter
        fail = True
424 2c035435 Guido Trotter
425 2c035435 Guido Trotter
    if fail:
426 14947dbc Iustin Pop
      raise BurninFailure()
427 14947dbc Iustin Pop
428 2c035435 Guido Trotter
    return val
429 21546b1c Iustin Pop
430 175f44c2 Iustin Pop
  def ParseOptions(self):
431 175f44c2 Iustin Pop
    """Parses the command line options.
432 175f44c2 Iustin Pop
433 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
434 175f44c2 Iustin Pop
    program.
435 175f44c2 Iustin Pop
436 175f44c2 Iustin Pop
    """
437 175f44c2 Iustin Pop
    parser = optparse.OptionParser(usage="\n%s" % USAGE,
438 10eb54fb Michael Hanselmann
                                   version=("%%prog (ganeti) %s" %
439 10eb54fb Michael Hanselmann
                                            constants.RELEASE_VERSION),
440 10eb54fb Michael Hanselmann
                                   option_list=OPTIONS)
441 175f44c2 Iustin Pop
442 175f44c2 Iustin Pop
    options, args = parser.parse_args()
443 175f44c2 Iustin Pop
    if len(args) < 1 or options.os is None:
444 175f44c2 Iustin Pop
      Usage()
445 175f44c2 Iustin Pop
446 f9193417 Iustin Pop
    supported_disk_templates = (constants.DT_DISKLESS,
447 2f505cb5 Manuel Franceschini
                                constants.DT_FILE,
448 f9193417 Iustin Pop
                                constants.DT_PLAIN,
449 12c3449a Michael Hanselmann
                                constants.DT_DRBD8)
450 12c3449a Michael Hanselmann
    if options.disk_template not in supported_disk_templates:
451 836d59d7 Iustin Pop
      Err("Unknown disk template '%s'" % options.disk_template)
452 175f44c2 Iustin Pop
453 b518a14a Iustin Pop
    if options.disk_template == constants.DT_DISKLESS:
454 b518a14a Iustin Pop
      disk_size = disk_growth = []
455 5178f1bc Iustin Pop
      options.do_addremove_disks = False
456 b518a14a Iustin Pop
    else:
457 b518a14a Iustin Pop
      disk_size = [utils.ParseUnit(v) for v in options.disk_size.split(",")]
458 b518a14a Iustin Pop
      disk_growth = [utils.ParseUnit(v)
459 b518a14a Iustin Pop
                     for v in options.disk_growth.split(",")]
460 b518a14a Iustin Pop
      if len(disk_growth) != len(disk_size):
461 836d59d7 Iustin Pop
        Err("Wrong disk sizes/growth combination")
462 08db7c5c Iustin Pop
    if ((disk_size and options.disk_template == constants.DT_DISKLESS) or
463 08db7c5c Iustin Pop
        (not disk_size and options.disk_template != constants.DT_DISKLESS)):
464 836d59d7 Iustin Pop
      Err("Wrong disk count/disk template combination")
465 08db7c5c Iustin Pop
466 08db7c5c Iustin Pop
    self.disk_size = disk_size
467 08db7c5c Iustin Pop
    self.disk_growth = disk_growth
468 08db7c5c Iustin Pop
    self.disk_count = len(disk_size)
469 08db7c5c Iustin Pop
470 b91bde14 Iustin Pop
    if options.nodes and options.iallocator:
471 836d59d7 Iustin Pop
      Err("Give either the nodes option or the iallocator option, not both")
472 b91bde14 Iustin Pop
473 544ca43b Iustin Pop
    if options.http_check and not options.name_check:
474 544ca43b Iustin Pop
      Err("Can't enable HTTP checks without name checks")
475 544ca43b Iustin Pop
476 175f44c2 Iustin Pop
    self.opts = options
477 175f44c2 Iustin Pop
    self.instances = args
478 338e51e8 Iustin Pop
    self.bep = {
479 338e51e8 Iustin Pop
      constants.BE_MEMORY: options.mem_size,
480 338e51e8 Iustin Pop
      constants.BE_VCPUS: 1,
481 338e51e8 Iustin Pop
      }
482 aac0352d Iustin Pop
483 aac0352d Iustin Pop
    self.hypervisor = None
484 338e51e8 Iustin Pop
    self.hvp = {}
485 aac0352d Iustin Pop
    if options.hypervisor:
486 aac0352d Iustin Pop
      self.hypervisor, self.hvp = options.hypervisor
487 175f44c2 Iustin Pop
488 1d103c02 Iustin Pop
    if options.reboot_types is None:
489 1d103c02 Iustin Pop
      options.reboot_types = constants.REBOOT_TYPES
490 1d103c02 Iustin Pop
    else:
491 1d103c02 Iustin Pop
      options.reboot_types = options.reboot_types.split(",")
492 1d103c02 Iustin Pop
      rt_diff = set(options.reboot_types).difference(constants.REBOOT_TYPES)
493 1d103c02 Iustin Pop
      if rt_diff:
494 1d103c02 Iustin Pop
        Err("Invalid reboot types specified: %s" % utils.CommaJoin(rt_diff))
495 1d103c02 Iustin Pop
496 5178f1bc Iustin Pop
    socket.setdefaulttimeout(options.net_timeout)
497 5178f1bc Iustin Pop
498 175f44c2 Iustin Pop
  def GetState(self):
499 be0636e3 Guido Trotter
    """Read the cluster state from the master daemon."""
500 175f44c2 Iustin Pop
    if self.opts.nodes:
501 175f44c2 Iustin Pop
      names = self.opts.nodes.split(",")
502 175f44c2 Iustin Pop
    else:
503 175f44c2 Iustin Pop
      names = []
504 175f44c2 Iustin Pop
    try:
505 e8d47209 Iustin Pop
      op = opcodes.OpQueryNodes(output_fields=["name", "offline", "drained"],
506 ec79568d Iustin Pop
                                names=names, use_locking=True)
507 73ff3118 Iustin Pop
      result = self.ExecOp(True, op)
508 175f44c2 Iustin Pop
    except errors.GenericError, err:
509 175f44c2 Iustin Pop
      err_code, msg = cli.FormatError(err)
510 836d59d7 Iustin Pop
      Err(msg, exit_code=err_code)
511 e8d47209 Iustin Pop
    self.nodes = [data[0] for data in result if not (data[1] or data[2])]
512 175f44c2 Iustin Pop
513 e3ac208c Guido Trotter
    op_diagnose = opcodes.OpDiagnoseOS(output_fields=["name", "valid",
514 e3ac208c Guido Trotter
                                                      "variants"], names=[])
515 e3ac208c Guido Trotter
    result = self.ExecOp(True, op_diagnose)
516 175f44c2 Iustin Pop
517 175f44c2 Iustin Pop
    if not result:
518 836d59d7 Iustin Pop
      Err("Can't get the OS list")
519 175f44c2 Iustin Pop
520 e3ac208c Guido Trotter
    found = False
521 e3ac208c Guido Trotter
    for (name, valid, variants) in result:
522 e3ac208c Guido Trotter
      if valid and self.opts.os in cli.CalculateOSNames(name, variants):
523 e3ac208c Guido Trotter
        found = True
524 e3ac208c Guido Trotter
        break
525 175f44c2 Iustin Pop
526 e3ac208c Guido Trotter
    if not found:
527 836d59d7 Iustin Pop
      Err("OS '%s' not found" % self.opts.os)
528 175f44c2 Iustin Pop
529 be0636e3 Guido Trotter
    cluster_info = self.cl.QueryClusterInfo()
530 be0636e3 Guido Trotter
    self.cluster_info = cluster_info
531 be0636e3 Guido Trotter
    if not self.cluster_info:
532 be0636e3 Guido Trotter
      Err("Can't get cluster info")
533 be0636e3 Guido Trotter
534 be0636e3 Guido Trotter
    default_nic_params = self.cluster_info["nicparams"][constants.PP_DEFAULT]
535 be0636e3 Guido Trotter
    self.cluster_default_nicparams = default_nic_params
536 aac0352d Iustin Pop
    if self.hypervisor is None:
537 aac0352d Iustin Pop
      self.hypervisor = self.cluster_info["default_hypervisor"]
538 aac0352d Iustin Pop
    self.hv_class = hypervisor.GetHypervisorClass(self.hypervisor)
539 be0636e3 Guido Trotter
540 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
541 c70481ab Iustin Pop
  @_DoBatch(False)
542 c723c163 Iustin Pop
  def BurnCreateInstances(self):
543 175f44c2 Iustin Pop
    """Create the given instances.
544 175f44c2 Iustin Pop
545 175f44c2 Iustin Pop
    """
546 175f44c2 Iustin Pop
    self.to_rem = []
547 175f44c2 Iustin Pop
    mytor = izip(cycle(self.nodes),
548 175f44c2 Iustin Pop
                 islice(cycle(self.nodes), 1, None),
549 175f44c2 Iustin Pop
                 self.instances)
550 338e51e8 Iustin Pop
551 836d59d7 Iustin Pop
    Log("Creating instances")
552 175f44c2 Iustin Pop
    for pnode, snode, instance in mytor:
553 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
554 b91bde14 Iustin Pop
      if self.opts.iallocator:
555 b91bde14 Iustin Pop
        pnode = snode = None
556 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
557 6d54548e Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
558 6d54548e Guido Trotter
        snode = None
559 836d59d7 Iustin Pop
        msg = "on %s" % pnode
560 6d54548e Guido Trotter
      else:
561 836d59d7 Iustin Pop
        msg = "on %s, %s" % (pnode, snode)
562 836d59d7 Iustin Pop
563 836d59d7 Iustin Pop
      Log(msg, indent=2)
564 6d54548e Guido Trotter
565 175f44c2 Iustin Pop
      op = opcodes.OpCreateInstance(instance_name=instance,
566 08db7c5c Iustin Pop
                                    disks = [ {"size": size}
567 08db7c5c Iustin Pop
                                              for size in self.disk_size],
568 175f44c2 Iustin Pop
                                    disk_template=self.opts.disk_template,
569 b518a14a Iustin Pop
                                    nics=self.opts.nics,
570 a8083063 Iustin Pop
                                    mode=constants.INSTANCE_CREATE,
571 175f44c2 Iustin Pop
                                    os_type=self.opts.os,
572 175f44c2 Iustin Pop
                                    pnode=pnode,
573 175f44c2 Iustin Pop
                                    snode=snode,
574 a8083063 Iustin Pop
                                    start=True,
575 544ca43b Iustin Pop
                                    ip_check=self.opts.ip_check,
576 544ca43b Iustin Pop
                                    name_check=self.opts.name_check,
577 4501af56 Iustin Pop
                                    wait_for_sync=True,
578 2f505cb5 Manuel Franceschini
                                    file_driver="loop",
579 b91bde14 Iustin Pop
                                    file_storage_dir=None,
580 6e2dc934 Alexander Schreiber
                                    iallocator=self.opts.iallocator,
581 338e51e8 Iustin Pop
                                    beparams=self.bep,
582 338e51e8 Iustin Pop
                                    hvparams=self.hvp,
583 aac0352d Iustin Pop
                                    hypervisor=self.hypervisor,
584 062a7100 Iustin Pop
                                    osparams=self.opts.osparams,
585 338e51e8 Iustin Pop
                                    )
586 1e82a86b Guido Trotter
      remove_instance = lambda name: lambda: self.to_rem.append(name)
587 1e82a86b Guido Trotter
      self.ExecOrQueue(instance, [op], post_process=remove_instance(instance))
588 c723c163 Iustin Pop
589 c70481ab Iustin Pop
  @_DoBatch(False)
590 c723c163 Iustin Pop
  def BurnGrowDisks(self):
591 659712c8 Iustin Pop
    """Grow both the os and the swap disks by the requested amount, if any."""
592 836d59d7 Iustin Pop
    Log("Growing disks")
593 659712c8 Iustin Pop
    for instance in self.instances:
594 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
595 08db7c5c Iustin Pop
      for idx, growth in enumerate(self.disk_growth):
596 659712c8 Iustin Pop
        if growth > 0:
597 08db7c5c Iustin Pop
          op = opcodes.OpGrowDisk(instance_name=instance, disk=idx,
598 6605411d Iustin Pop
                                  amount=growth, wait_for_sync=True)
599 1b334175 Iustin Pop
          Log("increase disk/%s by %s MB", idx, growth, indent=2)
600 b05f29a6 Guido Trotter
          self.ExecOrQueue(instance, [op])
601 659712c8 Iustin Pop
602 c70481ab Iustin Pop
  @_DoBatch(True)
603 c723c163 Iustin Pop
  def BurnReplaceDisks1D8(self):
604 175f44c2 Iustin Pop
    """Replace disks on primary and secondary for drbd8."""
605 836d59d7 Iustin Pop
    Log("Replacing disks on the same nodes")
606 175f44c2 Iustin Pop
    for instance in self.instances:
607 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
608 c723c163 Iustin Pop
      ops = []
609 175f44c2 Iustin Pop
      for mode in constants.REPLACE_DISK_SEC, constants.REPLACE_DISK_PRI:
610 175f44c2 Iustin Pop
        op = opcodes.OpReplaceDisks(instance_name=instance,
611 175f44c2 Iustin Pop
                                    mode=mode,
612 7ea7bcf6 Iustin Pop
                                    disks=[i for i in range(self.disk_count)],
613 7ea7bcf6 Iustin Pop
                                    early_release=self.opts.early_release)
614 1b334175 Iustin Pop
        Log("run %s", mode, indent=2)
615 c723c163 Iustin Pop
        ops.append(op)
616 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, ops)
617 175f44c2 Iustin Pop
618 c70481ab Iustin Pop
  @_DoBatch(True)
619 c723c163 Iustin Pop
  def BurnReplaceDisks2(self):
620 175f44c2 Iustin Pop
    """Replace secondary node."""
621 836d59d7 Iustin Pop
    Log("Changing the secondary node")
622 cfacfd6e Iustin Pop
    mode = constants.REPLACE_DISK_CHG
623 175f44c2 Iustin Pop
624 175f44c2 Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 2, None),
625 175f44c2 Iustin Pop
                 self.instances)
626 175f44c2 Iustin Pop
    for tnode, instance in mytor:
627 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
628 b6e82a65 Iustin Pop
      if self.opts.iallocator:
629 b6e82a65 Iustin Pop
        tnode = None
630 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
631 836d59d7 Iustin Pop
      else:
632 836d59d7 Iustin Pop
        msg = tnode
633 175f44c2 Iustin Pop
      op = opcodes.OpReplaceDisks(instance_name=instance,
634 175f44c2 Iustin Pop
                                  mode=mode,
635 175f44c2 Iustin Pop
                                  remote_node=tnode,
636 b6e82a65 Iustin Pop
                                  iallocator=self.opts.iallocator,
637 7ea7bcf6 Iustin Pop
                                  disks=[],
638 7ea7bcf6 Iustin Pop
                                  early_release=self.opts.early_release)
639 1b334175 Iustin Pop
      Log("run %s %s", mode, msg, indent=2)
640 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
641 175f44c2 Iustin Pop
642 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
643 c70481ab Iustin Pop
  @_DoBatch(False)
644 c723c163 Iustin Pop
  def BurnFailover(self):
645 175f44c2 Iustin Pop
    """Failover the instances."""
646 836d59d7 Iustin Pop
    Log("Failing over instances")
647 175f44c2 Iustin Pop
    for instance in self.instances:
648 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
649 175f44c2 Iustin Pop
      op = opcodes.OpFailoverInstance(instance_name=instance,
650 175f44c2 Iustin Pop
                                      ignore_consistency=False)
651 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
652 175f44c2 Iustin Pop
653 5b9107ff Iustin Pop
  @_DoCheckInstances
654 5b9107ff Iustin Pop
  @_DoBatch(False)
655 5b9107ff Iustin Pop
  def BurnMove(self):
656 5b9107ff Iustin Pop
    """Move the instances."""
657 5b9107ff Iustin Pop
    Log("Moving instances")
658 5b9107ff Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 1, None),
659 5b9107ff Iustin Pop
                 self.instances)
660 5b9107ff Iustin Pop
    for tnode, instance in mytor:
661 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
662 5b9107ff Iustin Pop
      op = opcodes.OpMoveInstance(instance_name=instance,
663 5b9107ff Iustin Pop
                                  target_node=tnode)
664 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
665 175f44c2 Iustin Pop
666 c70481ab Iustin Pop
  @_DoBatch(False)
667 c723c163 Iustin Pop
  def BurnMigrate(self):
668 99bdd139 Iustin Pop
    """Migrate the instances."""
669 801cda94 Iustin Pop
    Log("Migrating instances")
670 99bdd139 Iustin Pop
    for instance in self.instances:
671 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
672 f907fcf2 Iustin Pop
      op1 = opcodes.OpMigrateInstance(instance_name=instance, mode=None,
673 c723c163 Iustin Pop
                                      cleanup=False)
674 99bdd139 Iustin Pop
675 f907fcf2 Iustin Pop
      op2 = opcodes.OpMigrateInstance(instance_name=instance, mode=None,
676 c723c163 Iustin Pop
                                      cleanup=True)
677 c723c163 Iustin Pop
      Log("migration and migration cleanup", indent=2)
678 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2])
679 99bdd139 Iustin Pop
680 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
681 c70481ab Iustin Pop
  @_DoBatch(False)
682 c723c163 Iustin Pop
  def BurnImportExport(self):
683 bd5e77f9 Guido Trotter
    """Export the instance, delete it, and import it back.
684 bd5e77f9 Guido Trotter
685 bd5e77f9 Guido Trotter
    """
686 836d59d7 Iustin Pop
    Log("Exporting and re-importing instances")
687 bd5e77f9 Guido Trotter
    mytor = izip(cycle(self.nodes),
688 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 1, None),
689 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 2, None),
690 bd5e77f9 Guido Trotter
                 self.instances)
691 bd5e77f9 Guido Trotter
692 bd5e77f9 Guido Trotter
    for pnode, snode, enode, instance in mytor:
693 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
694 c723c163 Iustin Pop
      # read the full name of the instance
695 c723c163 Iustin Pop
      nam_op = opcodes.OpQueryInstances(output_fields=["name"],
696 ec79568d Iustin Pop
                                        names=[instance], use_locking=True)
697 73ff3118 Iustin Pop
      full_name = self.ExecOp(False, nam_op)[0][0]
698 c723c163 Iustin Pop
699 f9af35c8 Guido Trotter
      if self.opts.iallocator:
700 f9af35c8 Guido Trotter
        pnode = snode = None
701 836d59d7 Iustin Pop
        import_log_msg = ("import from %s"
702 836d59d7 Iustin Pop
                          " with iallocator %s" %
703 836d59d7 Iustin Pop
                          (enode, self.opts.iallocator))
704 f9af35c8 Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
705 f9af35c8 Guido Trotter
        snode = None
706 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s" %
707 836d59d7 Iustin Pop
                          (enode, pnode))
708 f9af35c8 Guido Trotter
      else:
709 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s, %s" %
710 836d59d7 Iustin Pop
                          (enode, pnode, snode))
711 f9af35c8 Guido Trotter
712 bd5e77f9 Guido Trotter
      exp_op = opcodes.OpExportInstance(instance_name=instance,
713 85edf27e Iustin Pop
                                        target_node=enode,
714 85edf27e Iustin Pop
                                        mode=constants.EXPORT_MODE_LOCAL,
715 85edf27e Iustin Pop
                                        shutdown=True)
716 5c54b832 Iustin Pop
      rem_op = opcodes.OpRemoveInstance(instance_name=instance,
717 5c54b832 Iustin Pop
                                        ignore_failures=True)
718 c4feafe8 Iustin Pop
      imp_dir = utils.PathJoin(constants.EXPORT_DIR, full_name)
719 bd5e77f9 Guido Trotter
      imp_op = opcodes.OpCreateInstance(instance_name=instance,
720 0ca35d45 Guido Trotter
                                        disks = [ {"size": size}
721 0ca35d45 Guido Trotter
                                                  for size in self.disk_size],
722 bd5e77f9 Guido Trotter
                                        disk_template=self.opts.disk_template,
723 b518a14a Iustin Pop
                                        nics=self.opts.nics,
724 bd5e77f9 Guido Trotter
                                        mode=constants.INSTANCE_IMPORT,
725 bd5e77f9 Guido Trotter
                                        src_node=enode,
726 bd5e77f9 Guido Trotter
                                        src_path=imp_dir,
727 bd5e77f9 Guido Trotter
                                        pnode=pnode,
728 bd5e77f9 Guido Trotter
                                        snode=snode,
729 bd5e77f9 Guido Trotter
                                        start=True,
730 544ca43b Iustin Pop
                                        ip_check=self.opts.ip_check,
731 544ca43b Iustin Pop
                                        name_check=self.opts.name_check,
732 bd5e77f9 Guido Trotter
                                        wait_for_sync=True,
733 96bb2f71 Manuel Franceschini
                                        file_storage_dir=None,
734 0ca35d45 Guido Trotter
                                        file_driver="loop",
735 6e2dc934 Alexander Schreiber
                                        iallocator=self.opts.iallocator,
736 338e51e8 Iustin Pop
                                        beparams=self.bep,
737 338e51e8 Iustin Pop
                                        hvparams=self.hvp,
738 062a7100 Iustin Pop
                                        osparams=self.opts.osparams,
739 338e51e8 Iustin Pop
                                        )
740 6e2dc934 Alexander Schreiber
741 4a7ff493 Guido Trotter
      erem_op = opcodes.OpRemoveExport(instance_name=instance)
742 bd5e77f9 Guido Trotter
743 1b334175 Iustin Pop
      Log("export to node %s", enode, indent=2)
744 836d59d7 Iustin Pop
      Log("remove instance", indent=2)
745 836d59d7 Iustin Pop
      Log(import_log_msg, indent=2)
746 836d59d7 Iustin Pop
      Log("remove export", indent=2)
747 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [exp_op, rem_op, imp_op, erem_op])
748 bd5e77f9 Guido Trotter
749 7e950d31 Iustin Pop
  @staticmethod
750 7e950d31 Iustin Pop
  def StopInstanceOp(instance):
751 054a8696 Manuel Franceschini
    """Stop given instance."""
752 c723c163 Iustin Pop
    return opcodes.OpShutdownInstance(instance_name=instance)
753 054a8696 Manuel Franceschini
754 7e950d31 Iustin Pop
  @staticmethod
755 7e950d31 Iustin Pop
  def StartInstanceOp(instance):
756 054a8696 Manuel Franceschini
    """Start given instance."""
757 c723c163 Iustin Pop
    return opcodes.OpStartupInstance(instance_name=instance, force=False)
758 054a8696 Manuel Franceschini
759 7e950d31 Iustin Pop
  @staticmethod
760 7e950d31 Iustin Pop
  def RenameInstanceOp(instance, instance_new):
761 054a8696 Manuel Franceschini
    """Rename instance."""
762 c723c163 Iustin Pop
    return opcodes.OpRenameInstance(instance_name=instance,
763 c723c163 Iustin Pop
                                    new_name=instance_new)
764 054a8696 Manuel Franceschini
765 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
766 c70481ab Iustin Pop
  @_DoBatch(True)
767 c723c163 Iustin Pop
  def BurnStopStart(self):
768 175f44c2 Iustin Pop
    """Stop/start the instances."""
769 836d59d7 Iustin Pop
    Log("Stopping and starting instances")
770 175f44c2 Iustin Pop
    for instance in self.instances:
771 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
772 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
773 c723c163 Iustin Pop
      op2 = self.StartInstanceOp(instance)
774 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2])
775 c723c163 Iustin Pop
776 c70481ab Iustin Pop
  @_DoBatch(False)
777 c723c163 Iustin Pop
  def BurnRemove(self):
778 175f44c2 Iustin Pop
    """Remove the instances."""
779 836d59d7 Iustin Pop
    Log("Removing instances")
780 175f44c2 Iustin Pop
    for instance in self.to_rem:
781 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
782 5c54b832 Iustin Pop
      op = opcodes.OpRemoveInstance(instance_name=instance,
783 5c54b832 Iustin Pop
                                    ignore_failures=True)
784 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
785 c723c163 Iustin Pop
786 c723c163 Iustin Pop
  def BurnRename(self):
787 c723c163 Iustin Pop
    """Rename the instances.
788 175f44c2 Iustin Pop
789 c723c163 Iustin Pop
    Note that this function will not execute in parallel, since we
790 c723c163 Iustin Pop
    only have one target for rename.
791 c723c163 Iustin Pop
792 c723c163 Iustin Pop
    """
793 836d59d7 Iustin Pop
    Log("Renaming instances")
794 054a8696 Manuel Franceschini
    rename = self.opts.rename
795 054a8696 Manuel Franceschini
    for instance in self.instances:
796 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
797 2e39ab98 Iustin Pop
      op_stop1 = self.StopInstanceOp(instance)
798 2e39ab98 Iustin Pop
      op_stop2 = self.StopInstanceOp(rename)
799 c723c163 Iustin Pop
      op_rename1 = self.RenameInstanceOp(instance, rename)
800 c723c163 Iustin Pop
      op_rename2 = self.RenameInstanceOp(rename, instance)
801 c723c163 Iustin Pop
      op_start1 = self.StartInstanceOp(rename)
802 c723c163 Iustin Pop
      op_start2 = self.StartInstanceOp(instance)
803 73ff3118 Iustin Pop
      self.ExecOp(False, op_stop1, op_rename1, op_start1)
804 5178f1bc Iustin Pop
      self._CheckInstanceAlive(rename)
805 73ff3118 Iustin Pop
      self.ExecOp(False, op_stop2, op_rename2, op_start2)
806 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
807 5178f1bc Iustin Pop
808 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
809 c70481ab Iustin Pop
  @_DoBatch(True)
810 c723c163 Iustin Pop
  def BurnReinstall(self):
811 00f91f29 Iustin Pop
    """Reinstall the instances."""
812 836d59d7 Iustin Pop
    Log("Reinstalling instances")
813 00f91f29 Iustin Pop
    for instance in self.instances:
814 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
815 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
816 c723c163 Iustin Pop
      op2 = opcodes.OpReinstallInstance(instance_name=instance)
817 836d59d7 Iustin Pop
      Log("reinstall without passing the OS", indent=2)
818 c723c163 Iustin Pop
      op3 = opcodes.OpReinstallInstance(instance_name=instance,
819 c723c163 Iustin Pop
                                        os_type=self.opts.os)
820 836d59d7 Iustin Pop
      Log("reinstall specifying the OS", indent=2)
821 c723c163 Iustin Pop
      op4 = self.StartInstanceOp(instance)
822 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2, op3, op4])
823 c723c163 Iustin Pop
824 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
825 c70481ab Iustin Pop
  @_DoBatch(True)
826 c723c163 Iustin Pop
  def BurnReboot(self):
827 836d59d7 Iustin Pop
    """Reboot the instances."""
828 836d59d7 Iustin Pop
    Log("Rebooting instances")
829 00f91f29 Iustin Pop
    for instance in self.instances:
830 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
831 c723c163 Iustin Pop
      ops = []
832 1d103c02 Iustin Pop
      for reboot_type in self.opts.reboot_types:
833 00f91f29 Iustin Pop
        op = opcodes.OpRebootInstance(instance_name=instance,
834 00f91f29 Iustin Pop
                                      reboot_type=reboot_type,
835 00f91f29 Iustin Pop
                                      ignore_secondaries=False)
836 1b334175 Iustin Pop
        Log("reboot with type '%s'", reboot_type, indent=2)
837 c723c163 Iustin Pop
        ops.append(op)
838 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, ops)
839 c723c163 Iustin Pop
840 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
841 c70481ab Iustin Pop
  @_DoBatch(True)
842 c723c163 Iustin Pop
  def BurnActivateDisks(self):
843 90e722d1 Iustin Pop
    """Activate and deactivate disks of the instances."""
844 836d59d7 Iustin Pop
    Log("Activating/deactivating disks")
845 90e722d1 Iustin Pop
    for instance in self.instances:
846 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
847 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
848 90e722d1 Iustin Pop
      op_act = opcodes.OpActivateInstanceDisks(instance_name=instance)
849 90e722d1 Iustin Pop
      op_deact = opcodes.OpDeactivateInstanceDisks(instance_name=instance)
850 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
851 836d59d7 Iustin Pop
      Log("activate disks when online", indent=2)
852 836d59d7 Iustin Pop
      Log("activate disks when offline", indent=2)
853 836d59d7 Iustin Pop
      Log("deactivate disks (when offline)", indent=2)
854 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_act, op_stop, op_act, op_deact, op_start])
855 90e722d1 Iustin Pop
856 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
857 c70481ab Iustin Pop
  @_DoBatch(False)
858 c723c163 Iustin Pop
  def BurnAddRemoveDisks(self):
859 5c22d16e Iustin Pop
    """Add and remove an extra disk for the instances."""
860 836d59d7 Iustin Pop
    Log("Adding and removing disks")
861 5c22d16e Iustin Pop
    for instance in self.instances:
862 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
863 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
864 5c22d16e Iustin Pop
        instance_name=instance,
865 5c22d16e Iustin Pop
        disks=[(constants.DDM_ADD, {"size": self.disk_size[0]})])
866 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
867 5c22d16e Iustin Pop
        instance_name=instance, disks=[(constants.DDM_REMOVE, {})])
868 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
869 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
870 836d59d7 Iustin Pop
      Log("adding a disk", indent=2)
871 836d59d7 Iustin Pop
      Log("removing last disk", indent=2)
872 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_add, op_stop, op_rem, op_start])
873 5c22d16e Iustin Pop
874 c70481ab Iustin Pop
  @_DoBatch(False)
875 c723c163 Iustin Pop
  def BurnAddRemoveNICs(self):
876 5c22d16e Iustin Pop
    """Add and remove an extra NIC for the instances."""
877 836d59d7 Iustin Pop
    Log("Adding and removing NICs")
878 5c22d16e Iustin Pop
    for instance in self.instances:
879 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
880 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
881 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_ADD, {})])
882 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
883 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_REMOVE, {})])
884 836d59d7 Iustin Pop
      Log("adding a NIC", indent=2)
885 836d59d7 Iustin Pop
      Log("removing last NIC", indent=2)
886 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_add, op_rem])
887 5c22d16e Iustin Pop
888 a619a1dd Guido Trotter
  def ConfdCallback(self, reply):
889 a619a1dd Guido Trotter
    """Callback for confd queries"""
890 a619a1dd Guido Trotter
    if reply.type == confd_client.UPCALL_REPLY:
891 a619a1dd Guido Trotter
      if reply.server_reply.status != constants.CONFD_REPL_STATUS_OK:
892 a619a1dd Guido Trotter
        Err("Query %s gave non-ok status %s: %s" % (reply.orig_request,
893 a619a1dd Guido Trotter
                                                    reply.server_reply.status,
894 a619a1dd Guido Trotter
                                                    reply.server_reply))
895 a619a1dd Guido Trotter
      if reply.orig_request.type == constants.CONFD_REQ_PING:
896 a619a1dd Guido Trotter
        Log("Ping: OK", indent=1)
897 a619a1dd Guido Trotter
      elif reply.orig_request.type == constants.CONFD_REQ_CLUSTER_MASTER:
898 a619a1dd Guido Trotter
        if reply.server_reply.answer == self.cluster_info["master"]:
899 a619a1dd Guido Trotter
          Log("Master: OK", indent=1)
900 a619a1dd Guido Trotter
        else:
901 a619a1dd Guido Trotter
          Err("Master: wrong: %s" % reply.server_reply.answer)
902 a619a1dd Guido Trotter
      elif reply.orig_request.type == constants.CONFD_REQ_NODE_ROLE_BYNAME:
903 a619a1dd Guido Trotter
        if reply.server_reply.answer == constants.CONFD_NODE_ROLE_MASTER:
904 a619a1dd Guido Trotter
          Log("Node role for master: OK", indent=1)
905 a619a1dd Guido Trotter
        else:
906 a619a1dd Guido Trotter
          Err("Node role for master: wrong: %s" % reply.server_reply.answer)
907 a619a1dd Guido Trotter
908 a619a1dd Guido Trotter
  def DoConfdRequestReply(self, req):
909 a619a1dd Guido Trotter
    self.confd_counting_callback.RegisterQuery(req.rsalt)
910 a619a1dd Guido Trotter
    self.confd_client.SendRequest(req, async=False)
911 a619a1dd Guido Trotter
    while not self.confd_counting_callback.AllAnswered():
912 a619a1dd Guido Trotter
      if not self.confd_client.ReceiveReply():
913 a619a1dd Guido Trotter
        Err("Did not receive all expected confd replies")
914 a619a1dd Guido Trotter
        break
915 a619a1dd Guido Trotter
916 a619a1dd Guido Trotter
  def BurnConfd(self):
917 a619a1dd Guido Trotter
    """Run confd queries for our instances.
918 a619a1dd Guido Trotter
919 a619a1dd Guido Trotter
    The following confd queries are tested:
920 454723b5 Iustin Pop
      - CONFD_REQ_PING: simple ping
921 454723b5 Iustin Pop
      - CONFD_REQ_CLUSTER_MASTER: cluster master
922 454723b5 Iustin Pop
      - CONFD_REQ_NODE_ROLE_BYNAME: node role, for the master
923 a619a1dd Guido Trotter
924 a619a1dd Guido Trotter
    """
925 a619a1dd Guido Trotter
    Log("Checking confd results")
926 a619a1dd Guido Trotter
927 a619a1dd Guido Trotter
    filter_callback = confd_client.ConfdFilterCallback(self.ConfdCallback)
928 a619a1dd Guido Trotter
    counting_callback = confd_client.ConfdCountingCallback(filter_callback)
929 a619a1dd Guido Trotter
    self.confd_counting_callback = counting_callback
930 a619a1dd Guido Trotter
931 5b349fd1 Iustin Pop
    self.confd_client = confd_client.GetConfdClient(counting_callback)
932 a619a1dd Guido Trotter
933 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
934 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
935 a619a1dd Guido Trotter
936 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(
937 a619a1dd Guido Trotter
      type=constants.CONFD_REQ_CLUSTER_MASTER)
938 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
939 a619a1dd Guido Trotter
940 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(
941 a619a1dd Guido Trotter
        type=constants.CONFD_REQ_NODE_ROLE_BYNAME,
942 a619a1dd Guido Trotter
        query=self.cluster_info["master"])
943 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
944 a619a1dd Guido Trotter
945 5178f1bc Iustin Pop
  def _CheckInstanceAlive(self, instance):
946 5178f1bc Iustin Pop
    """Check if an instance is alive by doing http checks.
947 5178f1bc Iustin Pop
948 5178f1bc Iustin Pop
    This will try to retrieve the url on the instance /hostname.txt
949 5178f1bc Iustin Pop
    and check that it contains the hostname of the instance. In case
950 5178f1bc Iustin Pop
    we get ECONNREFUSED, we retry up to the net timeout seconds, for
951 5178f1bc Iustin Pop
    any other error we abort.
952 5178f1bc Iustin Pop
953 5178f1bc Iustin Pop
    """
954 5178f1bc Iustin Pop
    if not self.opts.http_check:
955 5178f1bc Iustin Pop
      return
956 5dc626fd Iustin Pop
    end_time = time.time() + self.opts.net_timeout
957 5dc626fd Iustin Pop
    url = None
958 5dc626fd Iustin Pop
    while time.time() < end_time and url is None:
959 5dc626fd Iustin Pop
      try:
960 5dc626fd Iustin Pop
        url = self.url_opener.open("http://%s/hostname.txt" % instance)
961 c723c163 Iustin Pop
      except IOError:
962 5dc626fd Iustin Pop
        # here we can have connection refused, no route to host, etc.
963 5dc626fd Iustin Pop
        time.sleep(1)
964 5dc626fd Iustin Pop
    if url is None:
965 5dc626fd Iustin Pop
      raise InstanceDown(instance, "Cannot contact instance")
966 5178f1bc Iustin Pop
    hostname = url.read().strip()
967 5dc626fd Iustin Pop
    url.close()
968 5178f1bc Iustin Pop
    if hostname != instance:
969 5178f1bc Iustin Pop
      raise InstanceDown(instance, ("Hostname mismatch, expected %s, got %s" %
970 5178f1bc Iustin Pop
                                    (instance, hostname)))
971 5178f1bc Iustin Pop
972 175f44c2 Iustin Pop
  def BurninCluster(self):
973 175f44c2 Iustin Pop
    """Test a cluster intensively.
974 175f44c2 Iustin Pop
975 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
976 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
977 175f44c2 Iustin Pop
978 175f44c2 Iustin Pop
    """
979 175f44c2 Iustin Pop
980 175f44c2 Iustin Pop
    opts = self.opts
981 175f44c2 Iustin Pop
982 836d59d7 Iustin Pop
    Log("Testing global parameters")
983 175f44c2 Iustin Pop
984 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
985 2f505cb5 Manuel Franceschini
        opts.disk_template not in (constants.DT_DISKLESS, constants.DT_PLAIN,
986 2f505cb5 Manuel Franceschini
                                   constants.DT_FILE)):
987 836d59d7 Iustin Pop
      Err("When one node is available/selected the disk template must"
988 2f505cb5 Manuel Franceschini
          " be 'diskless', 'file' or 'plain'")
989 175f44c2 Iustin Pop
990 21546b1c Iustin Pop
    has_err = True
991 175f44c2 Iustin Pop
    try:
992 c723c163 Iustin Pop
      self.BurnCreateInstances()
993 175f44c2 Iustin Pop
      if opts.do_replace1 and opts.disk_template in constants.DTS_NET_MIRROR:
994 c723c163 Iustin Pop
        self.BurnReplaceDisks1D8()
995 175f44c2 Iustin Pop
      if (opts.do_replace2 and len(self.nodes) > 2 and
996 175f44c2 Iustin Pop
          opts.disk_template in constants.DTS_NET_MIRROR) :
997 c723c163 Iustin Pop
        self.BurnReplaceDisks2()
998 175f44c2 Iustin Pop
999 728489a3 Guido Trotter
      if (opts.disk_template in constants.DTS_GROWABLE and
1000 403f5172 Guido Trotter
          compat.any(n > 0 for n in self.disk_growth)):
1001 c723c163 Iustin Pop
        self.BurnGrowDisks()
1002 659712c8 Iustin Pop
1003 175f44c2 Iustin Pop
      if opts.do_failover and opts.disk_template in constants.DTS_NET_MIRROR:
1004 c723c163 Iustin Pop
        self.BurnFailover()
1005 175f44c2 Iustin Pop
1006 aac0352d Iustin Pop
      if opts.do_migrate:
1007 aac0352d Iustin Pop
        if opts.disk_template != constants.DT_DRBD8:
1008 aac0352d Iustin Pop
          Log("Skipping migration (disk template not DRBD8)")
1009 aac0352d Iustin Pop
        elif not self.hv_class.CAN_MIGRATE:
1010 aac0352d Iustin Pop
          Log("Skipping migration (hypervisor %s does not support it)",
1011 aac0352d Iustin Pop
              self.hypervisor)
1012 aac0352d Iustin Pop
        else:
1013 aac0352d Iustin Pop
          self.BurnMigrate()
1014 99bdd139 Iustin Pop
1015 9e32b93b Guido Trotter
      if (opts.do_move and len(self.nodes) > 1 and
1016 9e32b93b Guido Trotter
          opts.disk_template in [constants.DT_PLAIN, constants.DT_FILE]):
1017 5b9107ff Iustin Pop
        self.BurnMove()
1018 5b9107ff Iustin Pop
1019 a5e7be6b Iustin Pop
      if (opts.do_importexport and
1020 a5e7be6b Iustin Pop
          opts.disk_template not in (constants.DT_DISKLESS,
1021 a5e7be6b Iustin Pop
                                     constants.DT_FILE)):
1022 c723c163 Iustin Pop
        self.BurnImportExport()
1023 bd5e77f9 Guido Trotter
1024 00f91f29 Iustin Pop
      if opts.do_reinstall:
1025 c723c163 Iustin Pop
        self.BurnReinstall()
1026 00f91f29 Iustin Pop
1027 00f91f29 Iustin Pop
      if opts.do_reboot:
1028 c723c163 Iustin Pop
        self.BurnReboot()
1029 00f91f29 Iustin Pop
1030 5c22d16e Iustin Pop
      if opts.do_addremove_disks:
1031 c723c163 Iustin Pop
        self.BurnAddRemoveDisks()
1032 5c22d16e Iustin Pop
1033 be0636e3 Guido Trotter
      default_nic_mode = self.cluster_default_nicparams[constants.NIC_MODE]
1034 be0636e3 Guido Trotter
      # Don't add/remove nics in routed mode, as we would need an ip to add
1035 be0636e3 Guido Trotter
      # them with
1036 5c22d16e Iustin Pop
      if opts.do_addremove_nics:
1037 be0636e3 Guido Trotter
        if default_nic_mode == constants.NIC_MODE_BRIDGED:
1038 be0636e3 Guido Trotter
          self.BurnAddRemoveNICs()
1039 be0636e3 Guido Trotter
        else:
1040 be0636e3 Guido Trotter
          Log("Skipping nic add/remove as the cluster is not in bridged mode")
1041 5c22d16e Iustin Pop
1042 90e722d1 Iustin Pop
      if opts.do_activate_disks:
1043 c723c163 Iustin Pop
        self.BurnActivateDisks()
1044 90e722d1 Iustin Pop
1045 054a8696 Manuel Franceschini
      if opts.rename:
1046 c723c163 Iustin Pop
        self.BurnRename()
1047 054a8696 Manuel Franceschini
1048 a619a1dd Guido Trotter
      if opts.do_confd_tests:
1049 a619a1dd Guido Trotter
        self.BurnConfd()
1050 a619a1dd Guido Trotter
1051 eb61f8d3 Iustin Pop
      if opts.do_startstop:
1052 c723c163 Iustin Pop
        self.BurnStopStart()
1053 eb61f8d3 Iustin Pop
1054 21546b1c Iustin Pop
      has_err = False
1055 175f44c2 Iustin Pop
    finally:
1056 21546b1c Iustin Pop
      if has_err:
1057 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
1058 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
1059 21546b1c Iustin Pop
        Log("\n\n")
1060 320eda24 Iustin Pop
      if not self.opts.keep_instances:
1061 8629a543 Iustin Pop
        try:
1062 8629a543 Iustin Pop
          self.BurnRemove()
1063 7260cfbe Iustin Pop
        except Exception, err:  # pylint: disable-msg=W0703
1064 8629a543 Iustin Pop
          if has_err: # already detected errors, so errors in removal
1065 8629a543 Iustin Pop
                      # are quite expected
1066 1b334175 Iustin Pop
            Log("Note: error detected during instance remove: %s", err)
1067 8629a543 Iustin Pop
          else: # non-expected error
1068 8629a543 Iustin Pop
            raise
1069 175f44c2 Iustin Pop
1070 175f44c2 Iustin Pop
    return 0
1071 a8083063 Iustin Pop
1072 01b69ec5 Michael Hanselmann
1073 a8083063 Iustin Pop
def main():
1074 3ecf6786 Iustin Pop
  """Main function"""
1075 3ecf6786 Iustin Pop
1076 175f44c2 Iustin Pop
  burner = Burner()
1077 a4af651e Iustin Pop
  return burner.BurninCluster()
1078 a8083063 Iustin Pop
1079 01b69ec5 Michael Hanselmann
1080 a8083063 Iustin Pop
if __name__ == "__main__":
1081 3ecf6786 Iustin Pop
  main()