Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 36c70d4d

History | View | Annotate | Download (40.4 kB)

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