Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 3c286190

History | View | Annotate | Download (40.7 kB)

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