Statistics
| Branch: | Tag: | Revision:

root / lib / tools / burnin.py @ cfe9bed3

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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