Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ a7ea861a

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