Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ fcad7225

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