Statistics
| Branch: | Tag: | Revision:

root / lib / tools / burnin.py @ 178ad717

History | View | Annotate | Download (41.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 71dca138 Helga Velroyen
from ganeti.runtime import (GetClient)
45 a8083063 Iustin Pop
46 01b69ec5 Michael Hanselmann
47 9f13fc7a Iustin Pop
USAGE = ("\tburnin -o OS_NAME [options...] instance_name ...")
48 a8083063 Iustin Pop
49 73ff3118 Iustin Pop
MAX_RETRIES = 3
50 1b334175 Iustin Pop
LOG_HEADERS = {
51 1b334175 Iustin Pop
  0: "- ",
52 1b334175 Iustin Pop
  1: "* ",
53 3c286190 Dimitris Aragiorgis
  2: "",
54 1b334175 Iustin Pop
  }
55 01b69ec5 Michael Hanselmann
56 d8378091 Michael Hanselmann
#: Disk templates supporting a single node
57 d8378091 Michael Hanselmann
_SINGLE_NODE_DISK_TEMPLATES = compat.UniqueFrozenset([
58 d8378091 Michael Hanselmann
  constants.DT_DISKLESS,
59 d8378091 Michael Hanselmann
  constants.DT_PLAIN,
60 d8378091 Michael Hanselmann
  constants.DT_FILE,
61 d8378091 Michael Hanselmann
  constants.DT_SHARED_FILE,
62 85a895be Michael Hanselmann
  constants.DT_EXT,
63 85a895be Michael Hanselmann
  constants.DT_RBD,
64 8106dd64 Santi Raffa
  constants.DT_GLUSTER
65 d8378091 Michael Hanselmann
  ])
66 d8378091 Michael Hanselmann
67 d8378091 Michael Hanselmann
_SUPPORTED_DISK_TEMPLATES = compat.UniqueFrozenset([
68 d8378091 Michael Hanselmann
  constants.DT_DISKLESS,
69 d8378091 Michael Hanselmann
  constants.DT_DRBD8,
70 d8378091 Michael Hanselmann
  constants.DT_EXT,
71 d8378091 Michael Hanselmann
  constants.DT_FILE,
72 d8378091 Michael Hanselmann
  constants.DT_PLAIN,
73 d8378091 Michael Hanselmann
  constants.DT_RBD,
74 d8378091 Michael Hanselmann
  constants.DT_SHARED_FILE,
75 8106dd64 Santi Raffa
  constants.DT_GLUSTER
76 d8378091 Michael Hanselmann
  ])
77 d8378091 Michael Hanselmann
78 d8378091 Michael Hanselmann
#: Disk templates for which import/export is tested
79 d8378091 Michael Hanselmann
_IMPEXP_DISK_TEMPLATES = (_SUPPORTED_DISK_TEMPLATES - frozenset([
80 d8378091 Michael Hanselmann
  constants.DT_DISKLESS,
81 d8378091 Michael Hanselmann
  constants.DT_FILE,
82 d8378091 Michael Hanselmann
  constants.DT_SHARED_FILE,
83 8106dd64 Santi Raffa
  constants.DT_GLUSTER
84 d8378091 Michael Hanselmann
  ]))
85 d8378091 Michael Hanselmann
86 e687ec01 Michael Hanselmann
87 5178f1bc Iustin Pop
class InstanceDown(Exception):
88 5178f1bc Iustin Pop
  """The checked instance was not up"""
89 5178f1bc Iustin Pop
90 5178f1bc Iustin Pop
91 73ff3118 Iustin Pop
class BurninFailure(Exception):
92 73ff3118 Iustin Pop
  """Failure detected during burning"""
93 73ff3118 Iustin Pop
94 73ff3118 Iustin Pop
95 a8083063 Iustin Pop
def Usage():
96 a8083063 Iustin Pop
  """Shows program usage information and exits the program."""
97 a8083063 Iustin Pop
98 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
99 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
100 a8083063 Iustin Pop
  sys.exit(2)
101 a8083063 Iustin Pop
102 01b69ec5 Michael Hanselmann
103 1b334175 Iustin Pop
def Log(msg, *args, **kwargs):
104 3ecf6786 Iustin Pop
  """Simple function that prints out its argument.
105 3ecf6786 Iustin Pop

106 3ecf6786 Iustin Pop
  """
107 1b334175 Iustin Pop
  if args:
108 1b334175 Iustin Pop
    msg = msg % args
109 e687ec01 Michael Hanselmann
  indent = kwargs.get("indent", 0)
110 e687ec01 Michael Hanselmann
  sys.stdout.write("%*s%s%s\n" % (2 * indent, "",
111 1b334175 Iustin Pop
                                  LOG_HEADERS.get(indent, "  "), msg))
112 84cc52ab Michael Hanselmann
  sys.stdout.flush()
113 a8083063 Iustin Pop
114 1b334175 Iustin Pop
115 836d59d7 Iustin Pop
def Err(msg, exit_code=1):
116 836d59d7 Iustin Pop
  """Simple error logging that prints to stderr.
117 836d59d7 Iustin Pop

118 836d59d7 Iustin Pop
  """
119 836d59d7 Iustin Pop
  sys.stderr.write(msg + "\n")
120 836d59d7 Iustin Pop
  sys.stderr.flush()
121 836d59d7 Iustin Pop
  sys.exit(exit_code)
122 01b69ec5 Michael Hanselmann
123 5dc626fd Iustin Pop
124 5dc626fd Iustin Pop
class SimpleOpener(urllib.FancyURLopener):
125 5dc626fd Iustin Pop
  """A simple url opener"""
126 b459a848 Andrea Spadaccini
  # pylint: disable=W0221
127 5dc626fd Iustin Pop
128 7260cfbe Iustin Pop
  def prompt_user_passwd(self, host, realm, clear_cache=0):
129 5dc626fd Iustin Pop
    """No-interaction version of prompt_user_passwd."""
130 2d54e29c Iustin Pop
    # we follow parent class' API
131 b459a848 Andrea Spadaccini
    # pylint: disable=W0613
132 5dc626fd Iustin Pop
    return None, None
133 5dc626fd Iustin Pop
134 5dc626fd Iustin Pop
  def http_error_default(self, url, fp, errcode, errmsg, headers):
135 5dc626fd Iustin Pop
    """Custom error handling"""
136 5dc626fd Iustin Pop
    # make sure sockets are not left in CLOSE_WAIT, this is similar
137 5dc626fd Iustin Pop
    # but with a different exception to the BasicURLOpener class
138 5dc626fd Iustin Pop
    _ = fp.read() # throw away data
139 5dc626fd Iustin Pop
    fp.close()
140 5dc626fd Iustin Pop
    raise InstanceDown("HTTP error returned: code %s, msg %s" %
141 5dc626fd Iustin Pop
                       (errcode, errmsg))
142 5dc626fd Iustin Pop
143 5dc626fd Iustin Pop
144 10eb54fb Michael Hanselmann
OPTIONS = [
145 10eb54fb Michael Hanselmann
  cli.cli_option("-o", "--os", dest="os", default=None,
146 10eb54fb Michael Hanselmann
                 help="OS to use during burnin",
147 a52ba89d Michael Hanselmann
                 metavar="<OS>",
148 a52ba89d Michael Hanselmann
                 completion_suggest=cli.OPT_COMPL_ONE_OS),
149 aac0352d Iustin Pop
  cli.HYPERVISOR_OPT,
150 062a7100 Iustin Pop
  cli.OSPARAMS_OPT,
151 10eb54fb Michael Hanselmann
  cli.cli_option("--disk-size", dest="disk_size",
152 10eb54fb Michael Hanselmann
                 help="Disk size (determines disk count)",
153 10eb54fb Michael Hanselmann
                 default="128m", type="string", metavar="<size,size,...>",
154 10eb54fb Michael Hanselmann
                 completion_suggest=("128M 512M 1G 4G 1G,256M"
155 10eb54fb Michael Hanselmann
                                     " 4G,1G,1G 10G").split()),
156 10eb54fb Michael Hanselmann
  cli.cli_option("--disk-growth", dest="disk_growth", help="Disk growth",
157 10eb54fb Michael Hanselmann
                 default="128m", type="string", metavar="<size,size,...>"),
158 10eb54fb Michael Hanselmann
  cli.cli_option("--mem-size", dest="mem_size", help="Memory size",
159 6b5f0dd8 Guido Trotter
                 default=None, type="unit", metavar="<size>",
160 6b5f0dd8 Guido Trotter
                 completion_suggest=("128M 256M 512M 1G 4G 8G"
161 6b5f0dd8 Guido Trotter
                                     " 12G 16G").split()),
162 6b5f0dd8 Guido Trotter
  cli.cli_option("--maxmem-size", dest="maxmem_size", help="Max Memory size",
163 6b5f0dd8 Guido Trotter
                 default=256, type="unit", metavar="<size>",
164 6b5f0dd8 Guido Trotter
                 completion_suggest=("128M 256M 512M 1G 4G 8G"
165 6b5f0dd8 Guido Trotter
                                     " 12G 16G").split()),
166 6b5f0dd8 Guido Trotter
  cli.cli_option("--minmem-size", dest="minmem_size", help="Min Memory size",
167 10eb54fb Michael Hanselmann
                 default=128, type="unit", metavar="<size>",
168 10eb54fb Michael Hanselmann
                 completion_suggest=("128M 256M 512M 1G 4G 8G"
169 10eb54fb Michael Hanselmann
                                     " 12G 16G").split()),
170 d0ffa390 Pedro Macedo
  cli.cli_option("--vcpu-count", dest="vcpu_count", help="VCPU count",
171 d0ffa390 Pedro Macedo
                 default=3, type="unit", metavar="<count>",
172 d0ffa390 Pedro Macedo
                 completion_suggest=("1 2 3 4").split()),
173 265e6244 Iustin Pop
  cli.DEBUG_OPT,
174 9cdb9578 Iustin Pop
  cli.VERBOSE_OPT,
175 544ca43b Iustin Pop
  cli.NOIPCHECK_OPT,
176 544ca43b Iustin Pop
  cli.NONAMECHECK_OPT,
177 7ea7bcf6 Iustin Pop
  cli.EARLY_RELEASE_OPT,
178 10eb54fb Michael Hanselmann
  cli.cli_option("--no-replace1", dest="do_replace1",
179 10eb54fb Michael Hanselmann
                 help="Skip disk replacement with the same secondary",
180 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
181 10eb54fb Michael Hanselmann
  cli.cli_option("--no-replace2", dest="do_replace2",
182 10eb54fb Michael Hanselmann
                 help="Skip disk replacement with a different secondary",
183 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
184 10eb54fb Michael Hanselmann
  cli.cli_option("--no-failover", dest="do_failover",
185 10eb54fb Michael Hanselmann
                 help="Skip instance failovers", action="store_false",
186 10eb54fb Michael Hanselmann
                 default=True),
187 10eb54fb Michael Hanselmann
  cli.cli_option("--no-migrate", dest="do_migrate",
188 10eb54fb Michael Hanselmann
                 help="Skip instance live migration",
189 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
190 5b9107ff Iustin Pop
  cli.cli_option("--no-move", dest="do_move",
191 5b9107ff Iustin Pop
                 help="Skip instance moves", action="store_false",
192 5b9107ff Iustin Pop
                 default=True),
193 10eb54fb Michael Hanselmann
  cli.cli_option("--no-importexport", dest="do_importexport",
194 10eb54fb Michael Hanselmann
                 help="Skip instance export/import", action="store_false",
195 10eb54fb Michael Hanselmann
                 default=True),
196 10eb54fb Michael Hanselmann
  cli.cli_option("--no-startstop", dest="do_startstop",
197 10eb54fb Michael Hanselmann
                 help="Skip instance stop/start", action="store_false",
198 10eb54fb Michael Hanselmann
                 default=True),
199 10eb54fb Michael Hanselmann
  cli.cli_option("--no-reinstall", dest="do_reinstall",
200 10eb54fb Michael Hanselmann
                 help="Skip instance reinstall", action="store_false",
201 10eb54fb Michael Hanselmann
                 default=True),
202 10eb54fb Michael Hanselmann
  cli.cli_option("--no-reboot", dest="do_reboot",
203 10eb54fb Michael Hanselmann
                 help="Skip instance reboot", action="store_false",
204 10eb54fb Michael Hanselmann
                 default=True),
205 9fdc92fa Guido Trotter
  cli.cli_option("--no-renamesame", dest="do_renamesame",
206 9fdc92fa Guido Trotter
                 help="Skip instance rename to same name", action="store_false",
207 9fdc92fa Guido Trotter
                 default=True),
208 1d103c02 Iustin Pop
  cli.cli_option("--reboot-types", dest="reboot_types",
209 1d103c02 Iustin Pop
                 help="Specify the reboot types", default=None),
210 10eb54fb Michael Hanselmann
  cli.cli_option("--no-activate-disks", dest="do_activate_disks",
211 10eb54fb Michael Hanselmann
                 help="Skip disk activation/deactivation",
212 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
213 10eb54fb Michael Hanselmann
  cli.cli_option("--no-add-disks", dest="do_addremove_disks",
214 10eb54fb Michael Hanselmann
                 help="Skip disk addition/removal",
215 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
216 10eb54fb Michael Hanselmann
  cli.cli_option("--no-add-nics", dest="do_addremove_nics",
217 10eb54fb Michael Hanselmann
                 help="Skip NIC addition/removal",
218 10eb54fb Michael Hanselmann
                 action="store_false", default=True),
219 10eb54fb Michael Hanselmann
  cli.cli_option("--no-nics", dest="nics",
220 10eb54fb Michael Hanselmann
                 help="No network interfaces", action="store_const",
221 10eb54fb Michael Hanselmann
                 const=[], default=[{}]),
222 a619a1dd Guido Trotter
  cli.cli_option("--no-confd", dest="do_confd_tests",
223 a619a1dd Guido Trotter
                 help="Skip confd queries",
224 db3780f9 Iustin Pop
                 action="store_false", default=constants.ENABLE_CONFD),
225 10eb54fb Michael Hanselmann
  cli.cli_option("--rename", dest="rename", default=None,
226 10eb54fb Michael Hanselmann
                 help=("Give one unused instance name which is taken"
227 10eb54fb Michael Hanselmann
                       " to start the renaming sequence"),
228 10eb54fb Michael Hanselmann
                 metavar="<instance_name>"),
229 10eb54fb Michael Hanselmann
  cli.cli_option("-t", "--disk-template", dest="disk_template",
230 42959a7f Michael Hanselmann
                 choices=list(_SUPPORTED_DISK_TEMPLATES),
231 10eb54fb Michael Hanselmann
                 default=constants.DT_DRBD8,
232 42959a7f Michael Hanselmann
                 help=("Disk template (default %s, otherwise one of %s)" %
233 42959a7f Michael Hanselmann
                       (constants.DT_DRBD8,
234 42959a7f Michael Hanselmann
                        utils.CommaJoin(_SUPPORTED_DISK_TEMPLATES)))),
235 10eb54fb Michael Hanselmann
  cli.cli_option("-n", "--nodes", dest="nodes", default="",
236 10eb54fb Michael Hanselmann
                 help=("Comma separated list of nodes to perform"
237 a52ba89d Michael Hanselmann
                       " the burnin on (defaults to all nodes)"),
238 a52ba89d Michael Hanselmann
                 completion_suggest=cli.OPT_COMPL_MANY_NODES),
239 10eb54fb Michael Hanselmann
  cli.cli_option("-I", "--iallocator", dest="iallocator",
240 10eb54fb Michael Hanselmann
                 default=None, type="string",
241 10eb54fb Michael Hanselmann
                 help=("Perform the allocation using an iallocator"
242 10eb54fb Michael Hanselmann
                       " instead of fixed node spread (node restrictions no"
243 10eb54fb Michael Hanselmann
                       " longer apply, therefore -n/--nodes must not be"
244 a52ba89d Michael Hanselmann
                       " used"),
245 a52ba89d Michael Hanselmann
                 completion_suggest=cli.OPT_COMPL_ONE_IALLOCATOR),
246 10eb54fb Michael Hanselmann
  cli.cli_option("-p", "--parallel", default=False, action="store_true",
247 10eb54fb Michael Hanselmann
                 dest="parallel",
248 10eb54fb Michael Hanselmann
                 help=("Enable parallelization of some operations in"
249 10eb54fb Michael Hanselmann
                       " order to speed burnin or to test granular locking")),
250 10eb54fb Michael Hanselmann
  cli.cli_option("--net-timeout", default=15, type="int",
251 10eb54fb Michael Hanselmann
                 dest="net_timeout",
252 10eb54fb Michael Hanselmann
                 help=("The instance check network timeout in seconds"
253 10eb54fb Michael Hanselmann
                       " (defaults to 15 seconds)"),
254 10eb54fb Michael Hanselmann
                 completion_suggest="15 60 300 900".split()),
255 10eb54fb Michael Hanselmann
  cli.cli_option("-C", "--http-check", default=False, action="store_true",
256 10eb54fb Michael Hanselmann
                 dest="http_check",
257 10eb54fb Michael Hanselmann
                 help=("Enable checking of instance status via http,"
258 10eb54fb Michael Hanselmann
                       " looking for /hostname.txt that should contain the"
259 10eb54fb Michael Hanselmann
                       " name of the instance")),
260 10eb54fb Michael Hanselmann
  cli.cli_option("-K", "--keep-instances", default=False,
261 10eb54fb Michael Hanselmann
                 action="store_true",
262 10eb54fb Michael Hanselmann
                 dest="keep_instances",
263 10eb54fb Michael Hanselmann
                 help=("Leave instances on the cluster after burnin,"
264 10eb54fb Michael Hanselmann
                       " for investigation in case of errors or simply"
265 10eb54fb Michael Hanselmann
                       " to use them")),
266 bbfa259c Michele Tartara
  cli.REASON_OPT,
267 10eb54fb Michael Hanselmann
  ]
268 10eb54fb Michael Hanselmann
269 10eb54fb Michael Hanselmann
# Mainly used for bash completion
270 10eb54fb Michael Hanselmann
ARGUMENTS = [cli.ArgInstance(min=1)]
271 10eb54fb Michael Hanselmann
272 10eb54fb Michael Hanselmann
273 e7beaa02 Iustin Pop
def _DoCheckInstances(fn):
274 e7beaa02 Iustin Pop
  """Decorator for checking instances.
275 e7beaa02 Iustin Pop

276 e7beaa02 Iustin Pop
  """
277 e7beaa02 Iustin Pop
  def wrapper(self, *args, **kwargs):
278 e7beaa02 Iustin Pop
    val = fn(self, *args, **kwargs)
279 e7beaa02 Iustin Pop
    for instance in self.instances:
280 b459a848 Andrea Spadaccini
      self._CheckInstanceAlive(instance) # pylint: disable=W0212
281 e7beaa02 Iustin Pop
    return val
282 e7beaa02 Iustin Pop
283 e7beaa02 Iustin Pop
  return wrapper
284 e7beaa02 Iustin Pop
285 e7beaa02 Iustin Pop
286 e7beaa02 Iustin Pop
def _DoBatch(retry):
287 e7beaa02 Iustin Pop
  """Decorator for possible batch operations.
288 e7beaa02 Iustin Pop

289 e7beaa02 Iustin Pop
  Must come after the _DoCheckInstances decorator (if any).
290 e7beaa02 Iustin Pop

291 e7beaa02 Iustin Pop
  @param retry: whether this is a retryable batch, will be
292 e7beaa02 Iustin Pop
      passed to StartBatch
293 e7beaa02 Iustin Pop

294 e7beaa02 Iustin Pop
  """
295 e7beaa02 Iustin Pop
  def wrap(fn):
296 e7beaa02 Iustin Pop
    def batched(self, *args, **kwargs):
297 e7beaa02 Iustin Pop
      self.StartBatch(retry)
298 e7beaa02 Iustin Pop
      val = fn(self, *args, **kwargs)
299 e7beaa02 Iustin Pop
      self.CommitQueue()
300 e7beaa02 Iustin Pop
      return val
301 e7beaa02 Iustin Pop
    return batched
302 e7beaa02 Iustin Pop
303 e7beaa02 Iustin Pop
  return wrap
304 e7beaa02 Iustin Pop
305 e7beaa02 Iustin Pop
306 175f44c2 Iustin Pop
class Burner(object):
307 175f44c2 Iustin Pop
  """Burner class."""
308 175f44c2 Iustin Pop
309 175f44c2 Iustin Pop
  def __init__(self):
310 175f44c2 Iustin Pop
    """Constructor."""
311 5dc626fd Iustin Pop
    self.url_opener = SimpleOpener()
312 21546b1c Iustin Pop
    self._feed_buf = StringIO()
313 175f44c2 Iustin Pop
    self.nodes = []
314 175f44c2 Iustin Pop
    self.instances = []
315 175f44c2 Iustin Pop
    self.to_rem = []
316 c723c163 Iustin Pop
    self.queued_ops = []
317 175f44c2 Iustin Pop
    self.opts = None
318 73ff3118 Iustin Pop
    self.queue_retry = False
319 73ff3118 Iustin Pop
    self.disk_count = self.disk_growth = self.disk_size = None
320 73ff3118 Iustin Pop
    self.hvp = self.bep = None
321 175f44c2 Iustin Pop
    self.ParseOptions()
322 320eda24 Iustin Pop
    self.cl = cli.GetClient()
323 175f44c2 Iustin Pop
    self.GetState()
324 175f44c2 Iustin Pop
325 21546b1c Iustin Pop
  def ClearFeedbackBuf(self):
326 21546b1c Iustin Pop
    """Clear the feedback buffer."""
327 21546b1c Iustin Pop
    self._feed_buf.truncate(0)
328 21546b1c Iustin Pop
329 21546b1c Iustin Pop
  def GetFeedbackBuf(self):
330 21546b1c Iustin Pop
    """Return the contents of the buffer."""
331 21546b1c Iustin Pop
    return self._feed_buf.getvalue()
332 21546b1c Iustin Pop
333 21546b1c Iustin Pop
  def Feedback(self, msg):
334 21546b1c Iustin Pop
    """Acumulate feedback in our buffer."""
335 88d31e5c Iustin Pop
    formatted_msg = "%s %s" % (time.ctime(utils.MergeTime(msg[0])), msg[2])
336 88d31e5c Iustin Pop
    self._feed_buf.write(formatted_msg + "\n")
337 d7b47a77 Iustin Pop
    if self.opts.verbose:
338 88d31e5c Iustin Pop
      Log(formatted_msg, indent=3)
339 21546b1c Iustin Pop
340 73ff3118 Iustin Pop
  def MaybeRetry(self, retry_count, msg, fn, *args):
341 73ff3118 Iustin Pop
    """Possibly retry a given function execution.
342 73ff3118 Iustin Pop

343 73ff3118 Iustin Pop
    @type retry_count: int
344 73ff3118 Iustin Pop
    @param retry_count: retry counter:
345 73ff3118 Iustin Pop
        - 0: non-retryable action
346 73ff3118 Iustin Pop
        - 1: last retry for a retryable action
347 73ff3118 Iustin Pop
        - MAX_RETRIES: original try for a retryable action
348 73ff3118 Iustin Pop
    @type msg: str
349 73ff3118 Iustin Pop
    @param msg: the kind of the operation
350 73ff3118 Iustin Pop
    @type fn: callable
351 73ff3118 Iustin Pop
    @param fn: the function to be called
352 73ff3118 Iustin Pop

353 73ff3118 Iustin Pop
    """
354 73ff3118 Iustin Pop
    try:
355 73ff3118 Iustin Pop
      val = fn(*args)
356 73ff3118 Iustin Pop
      if retry_count > 0 and retry_count < MAX_RETRIES:
357 1b334175 Iustin Pop
        Log("Idempotent %s succeeded after %d retries",
358 1b334175 Iustin Pop
            msg, MAX_RETRIES - retry_count)
359 73ff3118 Iustin Pop
      return val
360 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
361 73ff3118 Iustin Pop
      if retry_count == 0:
362 1b334175 Iustin Pop
        Log("Non-idempotent %s failed, aborting", msg)
363 73ff3118 Iustin Pop
        raise
364 73ff3118 Iustin Pop
      elif retry_count == 1:
365 1b334175 Iustin Pop
        Log("Idempotent %s repeated failure, aborting", msg)
366 73ff3118 Iustin Pop
        raise
367 73ff3118 Iustin Pop
      else:
368 1b334175 Iustin Pop
        Log("Idempotent %s failed, retry #%d/%d: %s",
369 1b334175 Iustin Pop
            msg, MAX_RETRIES - retry_count + 1, MAX_RETRIES, err)
370 73ff3118 Iustin Pop
        self.MaybeRetry(retry_count - 1, msg, fn, *args)
371 73ff3118 Iustin Pop
372 73ff3118 Iustin Pop
  def _ExecOp(self, *ops):
373 c723c163 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
374 c723c163 Iustin Pop

375 454723b5 Iustin Pop
    @return: if only opcode has been passed, we return its result;
376 c723c163 Iustin Pop
        otherwise we return the list of results
377 c723c163 Iustin Pop

378 c723c163 Iustin Pop
    """
379 c723c163 Iustin Pop
    job_id = cli.SendJob(ops, cl=self.cl)
380 c723c163 Iustin Pop
    results = cli.PollJob(job_id, cl=self.cl, feedback_fn=self.Feedback)
381 c723c163 Iustin Pop
    if len(ops) == 1:
382 c723c163 Iustin Pop
      return results[0]
383 c723c163 Iustin Pop
    else:
384 c723c163 Iustin Pop
      return results
385 c723c163 Iustin Pop
386 73ff3118 Iustin Pop
  def ExecOp(self, retry, *ops):
387 73ff3118 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
388 73ff3118 Iustin Pop

389 454723b5 Iustin Pop
    @return: if only opcode has been passed, we return its result;
390 73ff3118 Iustin Pop
        otherwise we return the list of results
391 73ff3118 Iustin Pop

392 73ff3118 Iustin Pop
    """
393 73ff3118 Iustin Pop
    if retry:
394 73ff3118 Iustin Pop
      rval = MAX_RETRIES
395 73ff3118 Iustin Pop
    else:
396 73ff3118 Iustin Pop
      rval = 0
397 ddfde77e Michael Hanselmann
    cli.SetGenericOpcodeOpts(ops, self.opts)
398 73ff3118 Iustin Pop
    return self.MaybeRetry(rval, "opcode", self._ExecOp, *ops)
399 73ff3118 Iustin Pop
400 2c035435 Guido Trotter
  def ExecOrQueue(self, name, ops, post_process=None):
401 21546b1c Iustin Pop
    """Execute an opcode and manage the exec buffer."""
402 c723c163 Iustin Pop
    if self.opts.parallel:
403 ddfde77e Michael Hanselmann
      cli.SetGenericOpcodeOpts(ops, self.opts)
404 2c035435 Guido Trotter
      self.queued_ops.append((ops, name, post_process))
405 c723c163 Iustin Pop
    else:
406 b459a848 Andrea Spadaccini
      val = self.ExecOp(self.queue_retry, *ops) # pylint: disable=W0142
407 2c035435 Guido Trotter
      if post_process is not None:
408 2c035435 Guido Trotter
        post_process()
409 2c035435 Guido Trotter
      return val
410 73ff3118 Iustin Pop
411 73ff3118 Iustin Pop
  def StartBatch(self, retry):
412 73ff3118 Iustin Pop
    """Start a new batch of jobs.
413 73ff3118 Iustin Pop

414 73ff3118 Iustin Pop
    @param retry: whether this is a retryable batch
415 73ff3118 Iustin Pop

416 73ff3118 Iustin Pop
    """
417 73ff3118 Iustin Pop
    self.queued_ops = []
418 73ff3118 Iustin Pop
    self.queue_retry = retry
419 c723c163 Iustin Pop
420 c723c163 Iustin Pop
  def CommitQueue(self):
421 c723c163 Iustin Pop
    """Execute all submitted opcodes in case of parallel burnin"""
422 78bb78b1 Iustin Pop
    if not self.opts.parallel or not self.queued_ops:
423 c723c163 Iustin Pop
      return
424 c723c163 Iustin Pop
425 73ff3118 Iustin Pop
    if self.queue_retry:
426 73ff3118 Iustin Pop
      rval = MAX_RETRIES
427 73ff3118 Iustin Pop
    else:
428 73ff3118 Iustin Pop
      rval = 0
429 73ff3118 Iustin Pop
430 c723c163 Iustin Pop
    try:
431 73ff3118 Iustin Pop
      results = self.MaybeRetry(rval, "jobset", self.ExecJobSet,
432 73ff3118 Iustin Pop
                                self.queued_ops)
433 c723c163 Iustin Pop
    finally:
434 c723c163 Iustin Pop
      self.queued_ops = []
435 c723c163 Iustin Pop
    return results
436 ec5c88dc Iustin Pop
437 ec5c88dc Iustin Pop
  def ExecJobSet(self, jobs):
438 ec5c88dc Iustin Pop
    """Execute a set of jobs and return once all are done.
439 ec5c88dc Iustin Pop

440 ec5c88dc Iustin Pop
    The method will return the list of results, if all jobs are
441 c723c163 Iustin Pop
    successful. Otherwise, OpExecError will be raised from within
442 ec5c88dc Iustin Pop
    cli.py.
443 ec5c88dc Iustin Pop

444 ec5c88dc Iustin Pop
    """
445 ec5c88dc Iustin Pop
    self.ClearFeedbackBuf()
446 14947dbc Iustin Pop
    jex = cli.JobExecutor(cl=self.cl, feedback_fn=self.Feedback)
447 2c035435 Guido Trotter
    for ops, name, _ in jobs:
448 b459a848 Andrea Spadaccini
      jex.QueueJob(name, *ops) # pylint: disable=W0142
449 14947dbc Iustin Pop
    try:
450 14947dbc Iustin Pop
      results = jex.GetResults()
451 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
452 14947dbc Iustin Pop
      Log("Jobs failed: %s", err)
453 73ff3118 Iustin Pop
      raise BurninFailure()
454 14947dbc Iustin Pop
455 2c035435 Guido Trotter
    fail = False
456 2c035435 Guido Trotter
    val = []
457 2c035435 Guido Trotter
    for (_, name, post_process), (success, result) in zip(jobs, results):
458 2c035435 Guido Trotter
      if success:
459 2c035435 Guido Trotter
        if post_process:
460 2c035435 Guido Trotter
          try:
461 2c035435 Guido Trotter
            post_process()
462 b459a848 Andrea Spadaccini
          except Exception, err: # pylint: disable=W0703
463 2c035435 Guido Trotter
            Log("Post process call for job %s failed: %s", name, err)
464 2c035435 Guido Trotter
            fail = True
465 2c035435 Guido Trotter
        val.append(result)
466 2c035435 Guido Trotter
      else:
467 2c035435 Guido Trotter
        fail = True
468 2c035435 Guido Trotter
469 2c035435 Guido Trotter
    if fail:
470 14947dbc Iustin Pop
      raise BurninFailure()
471 14947dbc Iustin Pop
472 2c035435 Guido Trotter
    return val
473 21546b1c Iustin Pop
474 175f44c2 Iustin Pop
  def ParseOptions(self):
475 175f44c2 Iustin Pop
    """Parses the command line options.
476 175f44c2 Iustin Pop

477 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
478 175f44c2 Iustin Pop
    program.
479 175f44c2 Iustin Pop

480 175f44c2 Iustin Pop
    """
481 175f44c2 Iustin Pop
    parser = optparse.OptionParser(usage="\n%s" % USAGE,
482 10eb54fb Michael Hanselmann
                                   version=("%%prog (ganeti) %s" %
483 10eb54fb Michael Hanselmann
                                            constants.RELEASE_VERSION),
484 10eb54fb Michael Hanselmann
                                   option_list=OPTIONS)
485 175f44c2 Iustin Pop
486 175f44c2 Iustin Pop
    options, args = parser.parse_args()
487 175f44c2 Iustin Pop
    if len(args) < 1 or options.os is None:
488 175f44c2 Iustin Pop
      Usage()
489 175f44c2 Iustin Pop
490 6b5f0dd8 Guido Trotter
    if options.mem_size:
491 6b5f0dd8 Guido Trotter
      options.maxmem_size = options.mem_size
492 6b5f0dd8 Guido Trotter
      options.minmem_size = options.mem_size
493 6b5f0dd8 Guido Trotter
    elif options.minmem_size > options.maxmem_size:
494 6b5f0dd8 Guido Trotter
      Err("Maximum memory lower than minimum memory")
495 6b5f0dd8 Guido Trotter
496 d8378091 Michael Hanselmann
    if options.disk_template not in _SUPPORTED_DISK_TEMPLATES:
497 42959a7f Michael Hanselmann
      Err("Unknown or unsupported disk template '%s'" % options.disk_template)
498 175f44c2 Iustin Pop
499 b518a14a Iustin Pop
    if options.disk_template == constants.DT_DISKLESS:
500 b518a14a Iustin Pop
      disk_size = disk_growth = []
501 5178f1bc Iustin Pop
      options.do_addremove_disks = False
502 b518a14a Iustin Pop
    else:
503 b518a14a Iustin Pop
      disk_size = [utils.ParseUnit(v) for v in options.disk_size.split(",")]
504 b518a14a Iustin Pop
      disk_growth = [utils.ParseUnit(v)
505 b518a14a Iustin Pop
                     for v in options.disk_growth.split(",")]
506 b518a14a Iustin Pop
      if len(disk_growth) != len(disk_size):
507 836d59d7 Iustin Pop
        Err("Wrong disk sizes/growth combination")
508 08db7c5c Iustin Pop
    if ((disk_size and options.disk_template == constants.DT_DISKLESS) or
509 08db7c5c Iustin Pop
        (not disk_size and options.disk_template != constants.DT_DISKLESS)):
510 836d59d7 Iustin Pop
      Err("Wrong disk count/disk template combination")
511 08db7c5c Iustin Pop
512 08db7c5c Iustin Pop
    self.disk_size = disk_size
513 08db7c5c Iustin Pop
    self.disk_growth = disk_growth
514 08db7c5c Iustin Pop
    self.disk_count = len(disk_size)
515 08db7c5c Iustin Pop
516 b91bde14 Iustin Pop
    if options.nodes and options.iallocator:
517 836d59d7 Iustin Pop
      Err("Give either the nodes option or the iallocator option, not both")
518 b91bde14 Iustin Pop
519 544ca43b Iustin Pop
    if options.http_check and not options.name_check:
520 544ca43b Iustin Pop
      Err("Can't enable HTTP checks without name checks")
521 544ca43b Iustin Pop
522 175f44c2 Iustin Pop
    self.opts = options
523 175f44c2 Iustin Pop
    self.instances = args
524 338e51e8 Iustin Pop
    self.bep = {
525 6b5f0dd8 Guido Trotter
      constants.BE_MINMEM: options.minmem_size,
526 6b5f0dd8 Guido Trotter
      constants.BE_MAXMEM: options.maxmem_size,
527 d0ffa390 Pedro Macedo
      constants.BE_VCPUS: options.vcpu_count,
528 338e51e8 Iustin Pop
      }
529 aac0352d Iustin Pop
530 aac0352d Iustin Pop
    self.hypervisor = None
531 338e51e8 Iustin Pop
    self.hvp = {}
532 aac0352d Iustin Pop
    if options.hypervisor:
533 aac0352d Iustin Pop
      self.hypervisor, self.hvp = options.hypervisor
534 175f44c2 Iustin Pop
535 1d103c02 Iustin Pop
    if options.reboot_types is None:
536 1d103c02 Iustin Pop
      options.reboot_types = constants.REBOOT_TYPES
537 1d103c02 Iustin Pop
    else:
538 1d103c02 Iustin Pop
      options.reboot_types = options.reboot_types.split(",")
539 1d103c02 Iustin Pop
      rt_diff = set(options.reboot_types).difference(constants.REBOOT_TYPES)
540 1d103c02 Iustin Pop
      if rt_diff:
541 1d103c02 Iustin Pop
        Err("Invalid reboot types specified: %s" % utils.CommaJoin(rt_diff))
542 1d103c02 Iustin Pop
543 5178f1bc Iustin Pop
    socket.setdefaulttimeout(options.net_timeout)
544 5178f1bc Iustin Pop
545 175f44c2 Iustin Pop
  def GetState(self):
546 be0636e3 Guido Trotter
    """Read the cluster state from the master daemon."""
547 175f44c2 Iustin Pop
    if self.opts.nodes:
548 175f44c2 Iustin Pop
      names = self.opts.nodes.split(",")
549 175f44c2 Iustin Pop
    else:
550 175f44c2 Iustin Pop
      names = []
551 175f44c2 Iustin Pop
    try:
552 71dca138 Helga Velroyen
      qcl = GetClient(query=True)
553 71dca138 Helga Velroyen
      result = qcl.QueryNodes(names, ["name", "offline", "drained"], False)
554 175f44c2 Iustin Pop
    except errors.GenericError, err:
555 175f44c2 Iustin Pop
      err_code, msg = cli.FormatError(err)
556 836d59d7 Iustin Pop
      Err(msg, exit_code=err_code)
557 71dca138 Helga Velroyen
    finally:
558 71dca138 Helga Velroyen
      qcl.Close()
559 e8d47209 Iustin Pop
    self.nodes = [data[0] for data in result if not (data[1] or data[2])]
560 175f44c2 Iustin Pop
561 da2d02e7 Iustin Pop
    op_diagnose = opcodes.OpOsDiagnose(output_fields=["name",
562 eddc9815 Guido Trotter
                                                      "variants",
563 eddc9815 Guido Trotter
                                                      "hidden"],
564 d22dfef7 Iustin Pop
                                       names=[])
565 e3ac208c Guido Trotter
    result = self.ExecOp(True, op_diagnose)
566 175f44c2 Iustin Pop
567 175f44c2 Iustin Pop
    if not result:
568 836d59d7 Iustin Pop
      Err("Can't get the OS list")
569 175f44c2 Iustin Pop
570 e3ac208c Guido Trotter
    found = False
571 eddc9815 Guido Trotter
    for (name, variants, _) in result:
572 d22dfef7 Iustin Pop
      if self.opts.os in cli.CalculateOSNames(name, variants):
573 e3ac208c Guido Trotter
        found = True
574 e3ac208c Guido Trotter
        break
575 175f44c2 Iustin Pop
576 e3ac208c Guido Trotter
    if not found:
577 836d59d7 Iustin Pop
      Err("OS '%s' not found" % self.opts.os)
578 175f44c2 Iustin Pop
579 be0636e3 Guido Trotter
    cluster_info = self.cl.QueryClusterInfo()
580 be0636e3 Guido Trotter
    self.cluster_info = cluster_info
581 be0636e3 Guido Trotter
    if not self.cluster_info:
582 be0636e3 Guido Trotter
      Err("Can't get cluster info")
583 be0636e3 Guido Trotter
584 be0636e3 Guido Trotter
    default_nic_params = self.cluster_info["nicparams"][constants.PP_DEFAULT]
585 be0636e3 Guido Trotter
    self.cluster_default_nicparams = default_nic_params
586 aac0352d Iustin Pop
    if self.hypervisor is None:
587 aac0352d Iustin Pop
      self.hypervisor = self.cluster_info["default_hypervisor"]
588 94d5cee9 Michael Hanselmann
    self.hv_can_migrate = \
589 94d5cee9 Michael Hanselmann
      hypervisor.GetHypervisorClass(self.hypervisor).CAN_MIGRATE
590 be0636e3 Guido Trotter
591 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
592 c70481ab Iustin Pop
  @_DoBatch(False)
593 c723c163 Iustin Pop
  def BurnCreateInstances(self):
594 175f44c2 Iustin Pop
    """Create the given instances.
595 175f44c2 Iustin Pop

596 175f44c2 Iustin Pop
    """
597 175f44c2 Iustin Pop
    self.to_rem = []
598 175f44c2 Iustin Pop
    mytor = izip(cycle(self.nodes),
599 175f44c2 Iustin Pop
                 islice(cycle(self.nodes), 1, None),
600 175f44c2 Iustin Pop
                 self.instances)
601 338e51e8 Iustin Pop
602 836d59d7 Iustin Pop
    Log("Creating instances")
603 175f44c2 Iustin Pop
    for pnode, snode, instance in mytor:
604 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
605 b91bde14 Iustin Pop
      if self.opts.iallocator:
606 b91bde14 Iustin Pop
        pnode = snode = None
607 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
608 3429a076 Apollon Oikonomopoulos
      elif self.opts.disk_template not in constants.DTS_INT_MIRROR:
609 6d54548e Guido Trotter
        snode = None
610 836d59d7 Iustin Pop
        msg = "on %s" % pnode
611 6d54548e Guido Trotter
      else:
612 836d59d7 Iustin Pop
        msg = "on %s, %s" % (pnode, snode)
613 836d59d7 Iustin Pop
614 836d59d7 Iustin Pop
      Log(msg, indent=2)
615 6d54548e Guido Trotter
616 e1530b10 Iustin Pop
      op = opcodes.OpInstanceCreate(instance_name=instance,
617 e687ec01 Michael Hanselmann
                                    disks=[{"size": size}
618 e687ec01 Michael Hanselmann
                                           for size in self.disk_size],
619 175f44c2 Iustin Pop
                                    disk_template=self.opts.disk_template,
620 b518a14a Iustin Pop
                                    nics=self.opts.nics,
621 a8083063 Iustin Pop
                                    mode=constants.INSTANCE_CREATE,
622 175f44c2 Iustin Pop
                                    os_type=self.opts.os,
623 175f44c2 Iustin Pop
                                    pnode=pnode,
624 175f44c2 Iustin Pop
                                    snode=snode,
625 a8083063 Iustin Pop
                                    start=True,
626 544ca43b Iustin Pop
                                    ip_check=self.opts.ip_check,
627 544ca43b Iustin Pop
                                    name_check=self.opts.name_check,
628 4501af56 Iustin Pop
                                    wait_for_sync=True,
629 2f505cb5 Manuel Franceschini
                                    file_driver="loop",
630 b91bde14 Iustin Pop
                                    file_storage_dir=None,
631 6e2dc934 Alexander Schreiber
                                    iallocator=self.opts.iallocator,
632 338e51e8 Iustin Pop
                                    beparams=self.bep,
633 338e51e8 Iustin Pop
                                    hvparams=self.hvp,
634 aac0352d Iustin Pop
                                    hypervisor=self.hypervisor,
635 062a7100 Iustin Pop
                                    osparams=self.opts.osparams,
636 338e51e8 Iustin Pop
                                    )
637 1e82a86b Guido Trotter
      remove_instance = lambda name: lambda: self.to_rem.append(name)
638 1e82a86b Guido Trotter
      self.ExecOrQueue(instance, [op], post_process=remove_instance(instance))
639 c723c163 Iustin Pop
640 c70481ab Iustin Pop
  @_DoBatch(False)
641 6b5f0dd8 Guido Trotter
  def BurnModifyRuntimeMemory(self):
642 6b5f0dd8 Guido Trotter
    """Alter the runtime memory."""
643 6b5f0dd8 Guido Trotter
    Log("Setting instance runtime memory")
644 6b5f0dd8 Guido Trotter
    for instance in self.instances:
645 6b5f0dd8 Guido Trotter
      Log("instance %s", instance, indent=1)
646 6b5f0dd8 Guido Trotter
      tgt_mem = self.bep[constants.BE_MINMEM]
647 6b5f0dd8 Guido Trotter
      op = opcodes.OpInstanceSetParams(instance_name=instance,
648 6b5f0dd8 Guido Trotter
                                       runtime_mem=tgt_mem)
649 6b5f0dd8 Guido Trotter
      Log("Set memory to %s MB", tgt_mem, indent=2)
650 6b5f0dd8 Guido Trotter
      self.ExecOrQueue(instance, [op])
651 6b5f0dd8 Guido Trotter
652 6b5f0dd8 Guido Trotter
  @_DoBatch(False)
653 c723c163 Iustin Pop
  def BurnGrowDisks(self):
654 659712c8 Iustin Pop
    """Grow both the os and the swap disks by the requested amount, if any."""
655 836d59d7 Iustin Pop
    Log("Growing disks")
656 659712c8 Iustin Pop
    for instance in self.instances:
657 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
658 08db7c5c Iustin Pop
      for idx, growth in enumerate(self.disk_growth):
659 659712c8 Iustin Pop
        if growth > 0:
660 60472d29 Iustin Pop
          op = opcodes.OpInstanceGrowDisk(instance_name=instance, disk=idx,
661 60472d29 Iustin Pop
                                          amount=growth, wait_for_sync=True)
662 1b334175 Iustin Pop
          Log("increase disk/%s by %s MB", idx, growth, indent=2)
663 b05f29a6 Guido Trotter
          self.ExecOrQueue(instance, [op])
664 659712c8 Iustin Pop
665 c70481ab Iustin Pop
  @_DoBatch(True)
666 c723c163 Iustin Pop
  def BurnReplaceDisks1D8(self):
667 175f44c2 Iustin Pop
    """Replace disks on primary and secondary for drbd8."""
668 836d59d7 Iustin Pop
    Log("Replacing disks on the same nodes")
669 668f755d Iustin Pop
    early_release = self.opts.early_release
670 175f44c2 Iustin Pop
    for instance in self.instances:
671 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
672 c723c163 Iustin Pop
      ops = []
673 175f44c2 Iustin Pop
      for mode in constants.REPLACE_DISK_SEC, constants.REPLACE_DISK_PRI:
674 668f755d Iustin Pop
        op = opcodes.OpInstanceReplaceDisks(instance_name=instance,
675 668f755d Iustin Pop
                                            mode=mode,
676 668f755d Iustin Pop
                                            disks=list(range(self.disk_count)),
677 668f755d Iustin Pop
                                            early_release=early_release)
678 1b334175 Iustin Pop
        Log("run %s", mode, indent=2)
679 c723c163 Iustin Pop
        ops.append(op)
680 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, ops)
681 175f44c2 Iustin Pop
682 c70481ab Iustin Pop
  @_DoBatch(True)
683 c723c163 Iustin Pop
  def BurnReplaceDisks2(self):
684 175f44c2 Iustin Pop
    """Replace secondary node."""
685 836d59d7 Iustin Pop
    Log("Changing the secondary node")
686 cfacfd6e Iustin Pop
    mode = constants.REPLACE_DISK_CHG
687 175f44c2 Iustin Pop
688 175f44c2 Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 2, None),
689 175f44c2 Iustin Pop
                 self.instances)
690 175f44c2 Iustin Pop
    for tnode, instance in mytor:
691 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
692 b6e82a65 Iustin Pop
      if self.opts.iallocator:
693 b6e82a65 Iustin Pop
        tnode = None
694 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
695 836d59d7 Iustin Pop
      else:
696 836d59d7 Iustin Pop
        msg = tnode
697 668f755d Iustin Pop
      op = opcodes.OpInstanceReplaceDisks(instance_name=instance,
698 668f755d Iustin Pop
                                          mode=mode,
699 668f755d Iustin Pop
                                          remote_node=tnode,
700 668f755d Iustin Pop
                                          iallocator=self.opts.iallocator,
701 668f755d Iustin Pop
                                          disks=[],
702 668f755d Iustin Pop
                                          early_release=self.opts.early_release)
703 1b334175 Iustin Pop
      Log("run %s %s", mode, msg, indent=2)
704 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
705 175f44c2 Iustin Pop
706 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
707 c70481ab Iustin Pop
  @_DoBatch(False)
708 c723c163 Iustin Pop
  def BurnFailover(self):
709 175f44c2 Iustin Pop
    """Failover the instances."""
710 836d59d7 Iustin Pop
    Log("Failing over instances")
711 175f44c2 Iustin Pop
    for instance in self.instances:
712 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
713 019dbee1 Iustin Pop
      op = opcodes.OpInstanceFailover(instance_name=instance,
714 175f44c2 Iustin Pop
                                      ignore_consistency=False)
715 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
716 175f44c2 Iustin Pop
717 5b9107ff Iustin Pop
  @_DoCheckInstances
718 5b9107ff Iustin Pop
  @_DoBatch(False)
719 5b9107ff Iustin Pop
  def BurnMove(self):
720 5b9107ff Iustin Pop
    """Move the instances."""
721 5b9107ff Iustin Pop
    Log("Moving instances")
722 5b9107ff Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 1, None),
723 5b9107ff Iustin Pop
                 self.instances)
724 5b9107ff Iustin Pop
    for tnode, instance in mytor:
725 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
726 0091b480 Iustin Pop
      op = opcodes.OpInstanceMove(instance_name=instance,
727 5b9107ff Iustin Pop
                                  target_node=tnode)
728 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
729 175f44c2 Iustin Pop
730 c70481ab Iustin Pop
  @_DoBatch(False)
731 c723c163 Iustin Pop
  def BurnMigrate(self):
732 99bdd139 Iustin Pop
    """Migrate the instances."""
733 801cda94 Iustin Pop
    Log("Migrating instances")
734 99bdd139 Iustin Pop
    for instance in self.instances:
735 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
736 75c866c2 Iustin Pop
      op1 = opcodes.OpInstanceMigrate(instance_name=instance, mode=None,
737 c723c163 Iustin Pop
                                      cleanup=False)
738 99bdd139 Iustin Pop
739 75c866c2 Iustin Pop
      op2 = opcodes.OpInstanceMigrate(instance_name=instance, mode=None,
740 c723c163 Iustin Pop
                                      cleanup=True)
741 c723c163 Iustin Pop
      Log("migration and migration cleanup", indent=2)
742 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2])
743 99bdd139 Iustin Pop
744 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
745 c70481ab Iustin Pop
  @_DoBatch(False)
746 c723c163 Iustin Pop
  def BurnImportExport(self):
747 bd5e77f9 Guido Trotter
    """Export the instance, delete it, and import it back.
748 bd5e77f9 Guido Trotter

749 bd5e77f9 Guido Trotter
    """
750 836d59d7 Iustin Pop
    Log("Exporting and re-importing instances")
751 bd5e77f9 Guido Trotter
    mytor = izip(cycle(self.nodes),
752 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 1, None),
753 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 2, None),
754 bd5e77f9 Guido Trotter
                 self.instances)
755 bd5e77f9 Guido Trotter
756 71dca138 Helga Velroyen
    qcl = GetClient(query=True)
757 bd5e77f9 Guido Trotter
    for pnode, snode, enode, instance in mytor:
758 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
759 c723c163 Iustin Pop
      # read the full name of the instance
760 cfe9bed3 Helga Velroyen
      ((full_name, ), ) = qcl.QueryInstances([instance], ["name"], False)
761 c723c163 Iustin Pop
762 f9af35c8 Guido Trotter
      if self.opts.iallocator:
763 f9af35c8 Guido Trotter
        pnode = snode = None
764 836d59d7 Iustin Pop
        import_log_msg = ("import from %s"
765 836d59d7 Iustin Pop
                          " with iallocator %s" %
766 836d59d7 Iustin Pop
                          (enode, self.opts.iallocator))
767 3429a076 Apollon Oikonomopoulos
      elif self.opts.disk_template not in constants.DTS_INT_MIRROR:
768 f9af35c8 Guido Trotter
        snode = None
769 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s" %
770 836d59d7 Iustin Pop
                          (enode, pnode))
771 f9af35c8 Guido Trotter
      else:
772 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s, %s" %
773 836d59d7 Iustin Pop
                          (enode, pnode, snode))
774 f9af35c8 Guido Trotter
775 4ff922a2 Iustin Pop
      exp_op = opcodes.OpBackupExport(instance_name=instance,
776 4ff922a2 Iustin Pop
                                      target_node=enode,
777 4ff922a2 Iustin Pop
                                      mode=constants.EXPORT_MODE_LOCAL,
778 4ff922a2 Iustin Pop
                                      shutdown=True)
779 3cd2d4b1 Iustin Pop
      rem_op = opcodes.OpInstanceRemove(instance_name=instance,
780 5c54b832 Iustin Pop
                                        ignore_failures=True)
781 09bf5d24 Michael Hanselmann
      imp_dir = utils.PathJoin(pathutils.EXPORT_DIR, full_name)
782 e1530b10 Iustin Pop
      imp_op = opcodes.OpInstanceCreate(instance_name=instance,
783 e687ec01 Michael Hanselmann
                                        disks=[{"size": size}
784 e687ec01 Michael Hanselmann
                                               for size in self.disk_size],
785 bd5e77f9 Guido Trotter
                                        disk_template=self.opts.disk_template,
786 b518a14a Iustin Pop
                                        nics=self.opts.nics,
787 bd5e77f9 Guido Trotter
                                        mode=constants.INSTANCE_IMPORT,
788 bd5e77f9 Guido Trotter
                                        src_node=enode,
789 bd5e77f9 Guido Trotter
                                        src_path=imp_dir,
790 bd5e77f9 Guido Trotter
                                        pnode=pnode,
791 bd5e77f9 Guido Trotter
                                        snode=snode,
792 bd5e77f9 Guido Trotter
                                        start=True,
793 544ca43b Iustin Pop
                                        ip_check=self.opts.ip_check,
794 544ca43b Iustin Pop
                                        name_check=self.opts.name_check,
795 bd5e77f9 Guido Trotter
                                        wait_for_sync=True,
796 96bb2f71 Manuel Franceschini
                                        file_storage_dir=None,
797 0ca35d45 Guido Trotter
                                        file_driver="loop",
798 6e2dc934 Alexander Schreiber
                                        iallocator=self.opts.iallocator,
799 338e51e8 Iustin Pop
                                        beparams=self.bep,
800 338e51e8 Iustin Pop
                                        hvparams=self.hvp,
801 062a7100 Iustin Pop
                                        osparams=self.opts.osparams,
802 338e51e8 Iustin Pop
                                        )
803 6e2dc934 Alexander Schreiber
804 ca5890ad Iustin Pop
      erem_op = opcodes.OpBackupRemove(instance_name=instance)
805 bd5e77f9 Guido Trotter
806 1b334175 Iustin Pop
      Log("export to node %s", enode, indent=2)
807 836d59d7 Iustin Pop
      Log("remove instance", indent=2)
808 836d59d7 Iustin Pop
      Log(import_log_msg, indent=2)
809 836d59d7 Iustin Pop
      Log("remove export", indent=2)
810 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [exp_op, rem_op, imp_op, erem_op])
811 71dca138 Helga Velroyen
    qcl.Close()
812 bd5e77f9 Guido Trotter
813 7e950d31 Iustin Pop
  @staticmethod
814 7e950d31 Iustin Pop
  def StopInstanceOp(instance):
815 054a8696 Manuel Franceschini
    """Stop given instance."""
816 ee3e37a7 Iustin Pop
    return opcodes.OpInstanceShutdown(instance_name=instance)
817 054a8696 Manuel Franceschini
818 7e950d31 Iustin Pop
  @staticmethod
819 7e950d31 Iustin Pop
  def StartInstanceOp(instance):
820 054a8696 Manuel Franceschini
    """Start given instance."""
821 c873d91c Iustin Pop
    return opcodes.OpInstanceStartup(instance_name=instance, force=False)
822 054a8696 Manuel Franceschini
823 7e950d31 Iustin Pop
  @staticmethod
824 7e950d31 Iustin Pop
  def RenameInstanceOp(instance, instance_new):
825 054a8696 Manuel Franceschini
    """Rename instance."""
826 5659e2e2 Iustin Pop
    return opcodes.OpInstanceRename(instance_name=instance,
827 c723c163 Iustin Pop
                                    new_name=instance_new)
828 054a8696 Manuel Franceschini
829 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
830 c70481ab Iustin Pop
  @_DoBatch(True)
831 c723c163 Iustin Pop
  def BurnStopStart(self):
832 175f44c2 Iustin Pop
    """Stop/start the instances."""
833 836d59d7 Iustin Pop
    Log("Stopping and starting instances")
834 175f44c2 Iustin Pop
    for instance in self.instances:
835 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
836 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
837 c723c163 Iustin Pop
      op2 = self.StartInstanceOp(instance)
838 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2])
839 c723c163 Iustin Pop
840 c70481ab Iustin Pop
  @_DoBatch(False)
841 c723c163 Iustin Pop
  def BurnRemove(self):
842 175f44c2 Iustin Pop
    """Remove the instances."""
843 836d59d7 Iustin Pop
    Log("Removing instances")
844 175f44c2 Iustin Pop
    for instance in self.to_rem:
845 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
846 3cd2d4b1 Iustin Pop
      op = opcodes.OpInstanceRemove(instance_name=instance,
847 5c54b832 Iustin Pop
                                    ignore_failures=True)
848 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op])
849 c723c163 Iustin Pop
850 c723c163 Iustin Pop
  def BurnRename(self):
851 c723c163 Iustin Pop
    """Rename the instances.
852 175f44c2 Iustin Pop

853 c723c163 Iustin Pop
    Note that this function will not execute in parallel, since we
854 c723c163 Iustin Pop
    only have one target for rename.
855 c723c163 Iustin Pop

856 c723c163 Iustin Pop
    """
857 836d59d7 Iustin Pop
    Log("Renaming instances")
858 054a8696 Manuel Franceschini
    rename = self.opts.rename
859 054a8696 Manuel Franceschini
    for instance in self.instances:
860 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
861 2e39ab98 Iustin Pop
      op_stop1 = self.StopInstanceOp(instance)
862 2e39ab98 Iustin Pop
      op_stop2 = self.StopInstanceOp(rename)
863 c723c163 Iustin Pop
      op_rename1 = self.RenameInstanceOp(instance, rename)
864 c723c163 Iustin Pop
      op_rename2 = self.RenameInstanceOp(rename, instance)
865 c723c163 Iustin Pop
      op_start1 = self.StartInstanceOp(rename)
866 c723c163 Iustin Pop
      op_start2 = self.StartInstanceOp(instance)
867 73ff3118 Iustin Pop
      self.ExecOp(False, op_stop1, op_rename1, op_start1)
868 5178f1bc Iustin Pop
      self._CheckInstanceAlive(rename)
869 73ff3118 Iustin Pop
      self.ExecOp(False, op_stop2, op_rename2, op_start2)
870 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
871 5178f1bc Iustin Pop
872 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
873 c70481ab Iustin Pop
  @_DoBatch(True)
874 c723c163 Iustin Pop
  def BurnReinstall(self):
875 00f91f29 Iustin Pop
    """Reinstall the instances."""
876 836d59d7 Iustin Pop
    Log("Reinstalling instances")
877 00f91f29 Iustin Pop
    for instance in self.instances:
878 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
879 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
880 5073fd8f Iustin Pop
      op2 = opcodes.OpInstanceReinstall(instance_name=instance)
881 836d59d7 Iustin Pop
      Log("reinstall without passing the OS", indent=2)
882 5073fd8f Iustin Pop
      op3 = opcodes.OpInstanceReinstall(instance_name=instance,
883 c723c163 Iustin Pop
                                        os_type=self.opts.os)
884 836d59d7 Iustin Pop
      Log("reinstall specifying the OS", indent=2)
885 c723c163 Iustin Pop
      op4 = self.StartInstanceOp(instance)
886 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op1, op2, op3, op4])
887 c723c163 Iustin Pop
888 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
889 c70481ab Iustin Pop
  @_DoBatch(True)
890 c723c163 Iustin Pop
  def BurnReboot(self):
891 836d59d7 Iustin Pop
    """Reboot the instances."""
892 836d59d7 Iustin Pop
    Log("Rebooting instances")
893 00f91f29 Iustin Pop
    for instance in self.instances:
894 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
895 c723c163 Iustin Pop
      ops = []
896 1d103c02 Iustin Pop
      for reboot_type in self.opts.reboot_types:
897 90ab1a95 Iustin Pop
        op = opcodes.OpInstanceReboot(instance_name=instance,
898 00f91f29 Iustin Pop
                                      reboot_type=reboot_type,
899 00f91f29 Iustin Pop
                                      ignore_secondaries=False)
900 1b334175 Iustin Pop
        Log("reboot with type '%s'", reboot_type, indent=2)
901 c723c163 Iustin Pop
        ops.append(op)
902 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, ops)
903 c723c163 Iustin Pop
904 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
905 c70481ab Iustin Pop
  @_DoBatch(True)
906 9fdc92fa Guido Trotter
  def BurnRenameSame(self):
907 9fdc92fa Guido Trotter
    """Rename the instances to their own name."""
908 9fdc92fa Guido Trotter
    Log("Renaming the instances to their own name")
909 9fdc92fa Guido Trotter
    for instance in self.instances:
910 9fdc92fa Guido Trotter
      Log("instance %s", instance, indent=1)
911 9fdc92fa Guido Trotter
      op1 = self.StopInstanceOp(instance)
912 9fdc92fa Guido Trotter
      op2 = self.RenameInstanceOp(instance, instance)
913 9fdc92fa Guido Trotter
      Log("rename to the same name", indent=2)
914 9fdc92fa Guido Trotter
      op4 = self.StartInstanceOp(instance)
915 9fdc92fa Guido Trotter
      self.ExecOrQueue(instance, [op1, op2, op4])
916 9fdc92fa Guido Trotter
917 9fdc92fa Guido Trotter
  @_DoCheckInstances
918 9fdc92fa Guido Trotter
  @_DoBatch(True)
919 c723c163 Iustin Pop
  def BurnActivateDisks(self):
920 90e722d1 Iustin Pop
    """Activate and deactivate disks of the instances."""
921 836d59d7 Iustin Pop
    Log("Activating/deactivating disks")
922 90e722d1 Iustin Pop
    for instance in self.instances:
923 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
924 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
925 83f5d475 Iustin Pop
      op_act = opcodes.OpInstanceActivateDisks(instance_name=instance)
926 e176281f Iustin Pop
      op_deact = opcodes.OpInstanceDeactivateDisks(instance_name=instance)
927 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
928 836d59d7 Iustin Pop
      Log("activate disks when online", indent=2)
929 836d59d7 Iustin Pop
      Log("activate disks when offline", indent=2)
930 836d59d7 Iustin Pop
      Log("deactivate disks (when offline)", indent=2)
931 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_act, op_stop, op_act, op_deact, op_start])
932 90e722d1 Iustin Pop
933 d9b7a0b4 Iustin Pop
  @_DoCheckInstances
934 c70481ab Iustin Pop
  @_DoBatch(False)
935 c723c163 Iustin Pop
  def BurnAddRemoveDisks(self):
936 5c22d16e Iustin Pop
    """Add and remove an extra disk for the instances."""
937 836d59d7 Iustin Pop
    Log("Adding and removing disks")
938 5c22d16e Iustin Pop
    for instance in self.instances:
939 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
940 5ae4945a Iustin Pop
      op_add = opcodes.OpInstanceSetParams(
941 5c22d16e Iustin Pop
        instance_name=instance,
942 5c22d16e Iustin Pop
        disks=[(constants.DDM_ADD, {"size": self.disk_size[0]})])
943 5ae4945a Iustin Pop
      op_rem = opcodes.OpInstanceSetParams(
944 5c22d16e Iustin Pop
        instance_name=instance, disks=[(constants.DDM_REMOVE, {})])
945 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
946 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
947 836d59d7 Iustin Pop
      Log("adding a disk", indent=2)
948 836d59d7 Iustin Pop
      Log("removing last disk", indent=2)
949 b05f29a6 Guido Trotter
      self.ExecOrQueue(instance, [op_add, op_stop, op_rem, op_start])
950 5c22d16e Iustin Pop
951 c70481ab Iustin Pop
  @_DoBatch(False)
952 c723c163 Iustin Pop
  def BurnAddRemoveNICs(self):
953 0ccbf925 Iustin Pop
    """Add, change and remove an extra NIC for the instances."""
954 836d59d7 Iustin Pop
    Log("Adding and removing NICs")
955 5c22d16e Iustin Pop
    for instance in self.instances:
956 1b334175 Iustin Pop
      Log("instance %s", instance, indent=1)
957 5ae4945a Iustin Pop
      op_add = opcodes.OpInstanceSetParams(
958 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_ADD, {})])
959 5ae4945a Iustin Pop
      op_chg = opcodes.OpInstanceSetParams(
960 0ccbf925 Iustin Pop
        instance_name=instance, nics=[(constants.DDM_MODIFY,
961 0ccbf925 Iustin Pop
                                       -1, {"mac": constants.VALUE_GENERATE})])
962 5ae4945a Iustin Pop
      op_rem = opcodes.OpInstanceSetParams(
963 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_REMOVE, {})])
964 836d59d7 Iustin Pop
      Log("adding a NIC", indent=2)
965 0ccbf925 Iustin Pop
      Log("changing a NIC", indent=2)
966 836d59d7 Iustin Pop
      Log("removing last NIC", indent=2)
967 0ccbf925 Iustin Pop
      self.ExecOrQueue(instance, [op_add, op_chg, op_rem])
968 5c22d16e Iustin Pop
969 a619a1dd Guido Trotter
  def ConfdCallback(self, reply):
970 a619a1dd Guido Trotter
    """Callback for confd queries"""
971 a619a1dd Guido Trotter
    if reply.type == confd_client.UPCALL_REPLY:
972 a619a1dd Guido Trotter
      if reply.server_reply.status != constants.CONFD_REPL_STATUS_OK:
973 a619a1dd Guido Trotter
        Err("Query %s gave non-ok status %s: %s" % (reply.orig_request,
974 a619a1dd Guido Trotter
                                                    reply.server_reply.status,
975 a619a1dd Guido Trotter
                                                    reply.server_reply))
976 a619a1dd Guido Trotter
      if reply.orig_request.type == constants.CONFD_REQ_PING:
977 a619a1dd Guido Trotter
        Log("Ping: OK", indent=1)
978 a619a1dd Guido Trotter
      elif reply.orig_request.type == constants.CONFD_REQ_CLUSTER_MASTER:
979 a619a1dd Guido Trotter
        if reply.server_reply.answer == self.cluster_info["master"]:
980 a619a1dd Guido Trotter
          Log("Master: OK", indent=1)
981 a619a1dd Guido Trotter
        else:
982 a619a1dd Guido Trotter
          Err("Master: wrong: %s" % reply.server_reply.answer)
983 a619a1dd Guido Trotter
      elif reply.orig_request.type == constants.CONFD_REQ_NODE_ROLE_BYNAME:
984 a619a1dd Guido Trotter
        if reply.server_reply.answer == constants.CONFD_NODE_ROLE_MASTER:
985 a619a1dd Guido Trotter
          Log("Node role for master: OK", indent=1)
986 a619a1dd Guido Trotter
        else:
987 a619a1dd Guido Trotter
          Err("Node role for master: wrong: %s" % reply.server_reply.answer)
988 a619a1dd Guido Trotter
989 a619a1dd Guido Trotter
  def DoConfdRequestReply(self, req):
990 a619a1dd Guido Trotter
    self.confd_counting_callback.RegisterQuery(req.rsalt)
991 a619a1dd Guido Trotter
    self.confd_client.SendRequest(req, async=False)
992 a619a1dd Guido Trotter
    while not self.confd_counting_callback.AllAnswered():
993 a619a1dd Guido Trotter
      if not self.confd_client.ReceiveReply():
994 a619a1dd Guido Trotter
        Err("Did not receive all expected confd replies")
995 a619a1dd Guido Trotter
        break
996 a619a1dd Guido Trotter
997 a619a1dd Guido Trotter
  def BurnConfd(self):
998 a619a1dd Guido Trotter
    """Run confd queries for our instances.
999 a619a1dd Guido Trotter

1000 a619a1dd Guido Trotter
    The following confd queries are tested:
1001 454723b5 Iustin Pop
      - CONFD_REQ_PING: simple ping
1002 454723b5 Iustin Pop
      - CONFD_REQ_CLUSTER_MASTER: cluster master
1003 454723b5 Iustin Pop
      - CONFD_REQ_NODE_ROLE_BYNAME: node role, for the master
1004 a619a1dd Guido Trotter

1005 a619a1dd Guido Trotter
    """
1006 a619a1dd Guido Trotter
    Log("Checking confd results")
1007 a619a1dd Guido Trotter
1008 a619a1dd Guido Trotter
    filter_callback = confd_client.ConfdFilterCallback(self.ConfdCallback)
1009 a619a1dd Guido Trotter
    counting_callback = confd_client.ConfdCountingCallback(filter_callback)
1010 a619a1dd Guido Trotter
    self.confd_counting_callback = counting_callback
1011 a619a1dd Guido Trotter
1012 5b349fd1 Iustin Pop
    self.confd_client = confd_client.GetConfdClient(counting_callback)
1013 a619a1dd Guido Trotter
1014 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
1015 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
1016 a619a1dd Guido Trotter
1017 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(
1018 a619a1dd Guido Trotter
      type=constants.CONFD_REQ_CLUSTER_MASTER)
1019 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
1020 a619a1dd Guido Trotter
1021 a619a1dd Guido Trotter
    req = confd_client.ConfdClientRequest(
1022 a619a1dd Guido Trotter
        type=constants.CONFD_REQ_NODE_ROLE_BYNAME,
1023 a619a1dd Guido Trotter
        query=self.cluster_info["master"])
1024 a619a1dd Guido Trotter
    self.DoConfdRequestReply(req)
1025 a619a1dd Guido Trotter
1026 5178f1bc Iustin Pop
  def _CheckInstanceAlive(self, instance):
1027 5178f1bc Iustin Pop
    """Check if an instance is alive by doing http checks.
1028 5178f1bc Iustin Pop

1029 5178f1bc Iustin Pop
    This will try to retrieve the url on the instance /hostname.txt
1030 5178f1bc Iustin Pop
    and check that it contains the hostname of the instance. In case
1031 5178f1bc Iustin Pop
    we get ECONNREFUSED, we retry up to the net timeout seconds, for
1032 5178f1bc Iustin Pop
    any other error we abort.
1033 5178f1bc Iustin Pop

1034 5178f1bc Iustin Pop
    """
1035 5178f1bc Iustin Pop
    if not self.opts.http_check:
1036 5178f1bc Iustin Pop
      return
1037 5dc626fd Iustin Pop
    end_time = time.time() + self.opts.net_timeout
1038 5dc626fd Iustin Pop
    url = None
1039 5dc626fd Iustin Pop
    while time.time() < end_time and url is None:
1040 5dc626fd Iustin Pop
      try:
1041 5dc626fd Iustin Pop
        url = self.url_opener.open("http://%s/hostname.txt" % instance)
1042 c723c163 Iustin Pop
      except IOError:
1043 5dc626fd Iustin Pop
        # here we can have connection refused, no route to host, etc.
1044 5dc626fd Iustin Pop
        time.sleep(1)
1045 5dc626fd Iustin Pop
    if url is None:
1046 5dc626fd Iustin Pop
      raise InstanceDown(instance, "Cannot contact instance")
1047 5178f1bc Iustin Pop
    hostname = url.read().strip()
1048 5dc626fd Iustin Pop
    url.close()
1049 5178f1bc Iustin Pop
    if hostname != instance:
1050 5178f1bc Iustin Pop
      raise InstanceDown(instance, ("Hostname mismatch, expected %s, got %s" %
1051 5178f1bc Iustin Pop
                                    (instance, hostname)))
1052 5178f1bc Iustin Pop
1053 175f44c2 Iustin Pop
  def BurninCluster(self):
1054 175f44c2 Iustin Pop
    """Test a cluster intensively.
1055 175f44c2 Iustin Pop

1056 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
1057 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
1058 175f44c2 Iustin Pop

1059 175f44c2 Iustin Pop
    """
1060 175f44c2 Iustin Pop
1061 836d59d7 Iustin Pop
    Log("Testing global parameters")
1062 175f44c2 Iustin Pop
1063 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
1064 d0d7d7cf Thomas Thrainer
        self.opts.disk_template not in _SINGLE_NODE_DISK_TEMPLATES):
1065 836d59d7 Iustin Pop
      Err("When one node is available/selected the disk template must"
1066 d8378091 Michael Hanselmann
          " be one of %s" % utils.CommaJoin(_SINGLE_NODE_DISK_TEMPLATES))
1067 175f44c2 Iustin Pop
1068 d0d7d7cf Thomas Thrainer
    if self.opts.do_confd_tests and not constants.ENABLE_CONFD:
1069 db3780f9 Iustin Pop
      Err("You selected confd tests but confd was disabled at configure time")
1070 db3780f9 Iustin Pop
1071 21546b1c Iustin Pop
    has_err = True
1072 175f44c2 Iustin Pop
    try:
1073 c723c163 Iustin Pop
      self.BurnCreateInstances()
1074 6b5f0dd8 Guido Trotter
1075 6b5f0dd8 Guido Trotter
      if self.bep[constants.BE_MINMEM] < self.bep[constants.BE_MAXMEM]:
1076 6b5f0dd8 Guido Trotter
        self.BurnModifyRuntimeMemory()
1077 6b5f0dd8 Guido Trotter
1078 d0d7d7cf Thomas Thrainer
      if self.opts.do_replace1 and \
1079 d0d7d7cf Thomas Thrainer
           self.opts.disk_template in constants.DTS_INT_MIRROR:
1080 c723c163 Iustin Pop
        self.BurnReplaceDisks1D8()
1081 d0d7d7cf Thomas Thrainer
      if (self.opts.do_replace2 and len(self.nodes) > 2 and
1082 d0d7d7cf Thomas Thrainer
          self.opts.disk_template in constants.DTS_INT_MIRROR):
1083 c723c163 Iustin Pop
        self.BurnReplaceDisks2()
1084 175f44c2 Iustin Pop
1085 d0d7d7cf Thomas Thrainer
      if (self.opts.disk_template in constants.DTS_GROWABLE and
1086 403f5172 Guido Trotter
          compat.any(n > 0 for n in self.disk_growth)):
1087 c723c163 Iustin Pop
        self.BurnGrowDisks()
1088 659712c8 Iustin Pop
1089 d0d7d7cf Thomas Thrainer
      if self.opts.do_failover and \
1090 d0d7d7cf Thomas Thrainer
           self.opts.disk_template in constants.DTS_MIRRORED:
1091 c723c163 Iustin Pop
        self.BurnFailover()
1092 175f44c2 Iustin Pop
1093 d0d7d7cf Thomas Thrainer
      if self.opts.do_migrate:
1094 d0d7d7cf Thomas Thrainer
        if self.opts.disk_template not in constants.DTS_MIRRORED:
1095 9869360c Apollon Oikonomopoulos
          Log("Skipping migration (disk template %s does not support it)",
1096 d0d7d7cf Thomas Thrainer
              self.opts.disk_template)
1097 94d5cee9 Michael Hanselmann
        elif not self.hv_can_migrate:
1098 aac0352d Iustin Pop
          Log("Skipping migration (hypervisor %s does not support it)",
1099 aac0352d Iustin Pop
              self.hypervisor)
1100 aac0352d Iustin Pop
        else:
1101 aac0352d Iustin Pop
          self.BurnMigrate()
1102 99bdd139 Iustin Pop
1103 d0d7d7cf Thomas Thrainer
      if (self.opts.do_move and len(self.nodes) > 1 and
1104 d0d7d7cf Thomas Thrainer
          self.opts.disk_template in [constants.DT_PLAIN, constants.DT_FILE]):
1105 5b9107ff Iustin Pop
        self.BurnMove()
1106 5b9107ff Iustin Pop
1107 d0d7d7cf Thomas Thrainer
      if (self.opts.do_importexport and
1108 d0d7d7cf Thomas Thrainer
          self.opts.disk_template in _IMPEXP_DISK_TEMPLATES):
1109 c723c163 Iustin Pop
        self.BurnImportExport()
1110 bd5e77f9 Guido Trotter
1111 d0d7d7cf Thomas Thrainer
      if self.opts.do_reinstall:
1112 c723c163 Iustin Pop
        self.BurnReinstall()
1113 00f91f29 Iustin Pop
1114 d0d7d7cf Thomas Thrainer
      if self.opts.do_reboot:
1115 c723c163 Iustin Pop
        self.BurnReboot()
1116 00f91f29 Iustin Pop
1117 d0d7d7cf Thomas Thrainer
      if self.opts.do_renamesame:
1118 9fdc92fa Guido Trotter
        self.BurnRenameSame()
1119 9fdc92fa Guido Trotter
1120 d0d7d7cf Thomas Thrainer
      if self.opts.do_addremove_disks:
1121 c723c163 Iustin Pop
        self.BurnAddRemoveDisks()
1122 5c22d16e Iustin Pop
1123 be0636e3 Guido Trotter
      default_nic_mode = self.cluster_default_nicparams[constants.NIC_MODE]
1124 be0636e3 Guido Trotter
      # Don't add/remove nics in routed mode, as we would need an ip to add
1125 be0636e3 Guido Trotter
      # them with
1126 d0d7d7cf Thomas Thrainer
      if self.opts.do_addremove_nics:
1127 be0636e3 Guido Trotter
        if default_nic_mode == constants.NIC_MODE_BRIDGED:
1128 be0636e3 Guido Trotter
          self.BurnAddRemoveNICs()
1129 be0636e3 Guido Trotter
        else:
1130 be0636e3 Guido Trotter
          Log("Skipping nic add/remove as the cluster is not in bridged mode")
1131 5c22d16e Iustin Pop
1132 d0d7d7cf Thomas Thrainer
      if self.opts.do_activate_disks:
1133 c723c163 Iustin Pop
        self.BurnActivateDisks()
1134 90e722d1 Iustin Pop
1135 d0d7d7cf Thomas Thrainer
      if self.opts.rename:
1136 c723c163 Iustin Pop
        self.BurnRename()
1137 054a8696 Manuel Franceschini
1138 d0d7d7cf Thomas Thrainer
      if self.opts.do_confd_tests:
1139 a619a1dd Guido Trotter
        self.BurnConfd()
1140 a619a1dd Guido Trotter
1141 d0d7d7cf Thomas Thrainer
      if self.opts.do_startstop:
1142 c723c163 Iustin Pop
        self.BurnStopStart()
1143 eb61f8d3 Iustin Pop
1144 21546b1c Iustin Pop
      has_err = False
1145 175f44c2 Iustin Pop
    finally:
1146 21546b1c Iustin Pop
      if has_err:
1147 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
1148 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
1149 21546b1c Iustin Pop
        Log("\n\n")
1150 320eda24 Iustin Pop
      if not self.opts.keep_instances:
1151 8629a543 Iustin Pop
        try:
1152 8629a543 Iustin Pop
          self.BurnRemove()
1153 b459a848 Andrea Spadaccini
        except Exception, err:  # pylint: disable=W0703
1154 8629a543 Iustin Pop
          if has_err: # already detected errors, so errors in removal
1155 8629a543 Iustin Pop
                      # are quite expected
1156 1b334175 Iustin Pop
            Log("Note: error detected during instance remove: %s", err)
1157 8629a543 Iustin Pop
          else: # non-expected error
1158 8629a543 Iustin Pop
            raise
1159 175f44c2 Iustin Pop
1160 3f17ef02 Michael Hanselmann
    return constants.EXIT_SUCCESS
1161 a8083063 Iustin Pop
1162 01b69ec5 Michael Hanselmann
1163 8e55e20f Michael Hanselmann
def Main():
1164 3f17ef02 Michael Hanselmann
  """Main function.
1165 3ecf6786 Iustin Pop

1166 3f17ef02 Michael Hanselmann
  """
1167 09bf5d24 Michael Hanselmann
  utils.SetupLogging(pathutils.LOG_BURNIN, sys.argv[0],
1168 cfcc79c6 Michael Hanselmann
                     debug=False, stderr_logging=True)
1169 3f17ef02 Michael Hanselmann
1170 3f17ef02 Michael Hanselmann
  return Burner().BurninCluster()