Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ a292020f

History | View | Annotate | Download (38.6 kB)

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