Statistics
| Branch: | Tag: | Revision:

root / lib / tools / burnin.py @ 84ad6b78

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 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 d8378091 Michael Hanselmann
#: Disk templates supporting a single node
56 d8378091 Michael Hanselmann
_SINGLE_NODE_DISK_TEMPLATES = compat.UniqueFrozenset([
57 d8378091 Michael Hanselmann
  constants.DT_DISKLESS,
58 d8378091 Michael Hanselmann
  constants.DT_PLAIN,
59 d8378091 Michael Hanselmann
  constants.DT_FILE,
60 d8378091 Michael Hanselmann
  constants.DT_SHARED_FILE,
61 85a895be Michael Hanselmann
  constants.DT_EXT,
62 85a895be Michael Hanselmann
  constants.DT_RBD,
63 d8378091 Michael Hanselmann
  ])
64 d8378091 Michael Hanselmann
65 d8378091 Michael Hanselmann
_SUPPORTED_DISK_TEMPLATES = compat.UniqueFrozenset([
66 d8378091 Michael Hanselmann
  constants.DT_DISKLESS,
67 d8378091 Michael Hanselmann
  constants.DT_DRBD8,
68 d8378091 Michael Hanselmann
  constants.DT_EXT,
69 d8378091 Michael Hanselmann
  constants.DT_FILE,
70 d8378091 Michael Hanselmann
  constants.DT_PLAIN,
71 d8378091 Michael Hanselmann
  constants.DT_RBD,
72 d8378091 Michael Hanselmann
  constants.DT_SHARED_FILE,
73 d8378091 Michael Hanselmann
  ])
74 d8378091 Michael Hanselmann
75 d8378091 Michael Hanselmann
#: Disk templates for which import/export is tested
76 d8378091 Michael Hanselmann
_IMPEXP_DISK_TEMPLATES = (_SUPPORTED_DISK_TEMPLATES - frozenset([
77 d8378091 Michael Hanselmann
  constants.DT_DISKLESS,
78 d8378091 Michael Hanselmann
  constants.DT_FILE,
79 d8378091 Michael Hanselmann
  constants.DT_SHARED_FILE,
80 d8378091 Michael Hanselmann
  ]))
81 d8378091 Michael Hanselmann
82 e687ec01 Michael Hanselmann
83 5178f1bc Iustin Pop
class InstanceDown(Exception):
84 5178f1bc Iustin Pop
  """The checked instance was not up"""
85 5178f1bc Iustin Pop
86 5178f1bc Iustin Pop
87 73ff3118 Iustin Pop
class BurninFailure(Exception):
88 73ff3118 Iustin Pop
  """Failure detected during burning"""
89 73ff3118 Iustin Pop
90 73ff3118 Iustin Pop
91 a8083063 Iustin Pop
def Usage():
92 a8083063 Iustin Pop
  """Shows program usage information and exits the program."""
93 a8083063 Iustin Pop
94 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
95 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
96 a8083063 Iustin Pop
  sys.exit(2)
97 a8083063 Iustin Pop
98 01b69ec5 Michael Hanselmann
99 1b334175 Iustin Pop
def Log(msg, *args, **kwargs):
100 3ecf6786 Iustin Pop
  """Simple function that prints out its argument.
101 3ecf6786 Iustin Pop

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

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

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

285 e7beaa02 Iustin Pop
  Must come after the _DoCheckInstances decorator (if any).
286 e7beaa02 Iustin Pop

287 e7beaa02 Iustin Pop
  @param retry: whether this is a retryable batch, will be
288 e7beaa02 Iustin Pop
      passed to StartBatch
289 e7beaa02 Iustin Pop

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

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

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

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

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

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

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

410 73ff3118 Iustin Pop
    @param retry: whether this is a retryable batch
411 73ff3118 Iustin Pop

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

436 ec5c88dc Iustin Pop
    The method will return the list of results, if all jobs are
437 c723c163 Iustin Pop
    successful. Otherwise, OpExecError will be raised from within
438 ec5c88dc Iustin Pop
    cli.py.
439 ec5c88dc Iustin Pop

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

473 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
474 175f44c2 Iustin Pop
    program.
475 175f44c2 Iustin Pop

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

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

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

848 c723c163 Iustin Pop
    Note that this function will not execute in parallel, since we
849 c723c163 Iustin Pop
    only have one target for rename.
850 c723c163 Iustin Pop

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

995 a619a1dd Guido Trotter
    The following confd queries are tested:
996 454723b5 Iustin Pop
      - CONFD_REQ_PING: simple ping
997 454723b5 Iustin Pop
      - CONFD_REQ_CLUSTER_MASTER: cluster master
998 454723b5 Iustin Pop
      - CONFD_REQ_NODE_ROLE_BYNAME: node role, for the master
999 a619a1dd Guido Trotter

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

1024 5178f1bc Iustin Pop
    This will try to retrieve the url on the instance /hostname.txt
1025 5178f1bc Iustin Pop
    and check that it contains the hostname of the instance. In case
1026 5178f1bc Iustin Pop
    we get ECONNREFUSED, we retry up to the net timeout seconds, for
1027 5178f1bc Iustin Pop
    any other error we abort.
1028 5178f1bc Iustin Pop

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

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

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

1161 3f17ef02 Michael Hanselmann
  """
1162 09bf5d24 Michael Hanselmann
  utils.SetupLogging(pathutils.LOG_BURNIN, sys.argv[0],
1163 cfcc79c6 Michael Hanselmann
                     debug=False, stderr_logging=True)
1164 3f17ef02 Michael Hanselmann
1165 3f17ef02 Michael Hanselmann
  return Burner().BurninCluster()