Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ aac0352d

History | View | Annotate | Download (37.5 kB)

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